How to do a Task Manager 'Switch To'?

  • Thread starter Thread starter N M
  • Start date Start date
N

N M

Hi all,

I've been scratching my head (to the bone) try to find a way of
switching from one .Net application to another. ie. I click a button
on a controller application and the other one is brought to the front.

I even have a Process object pointing to the application I want to
activate, but I can't seem to find any way of using this.

The purpose of the controller application is to provide a single
interface to launch/terminate/switch to a suite of programs without
having loads of applications in either the task bar or the system
tray.

Herein lies the problem. In order to hide the application when it is
minimised, I have to either sets its ShowInTaskBar property to false
or just hide it. The trouble is, when you do this you lose the handle
as there isn't a window anymore. I tried using the API calls
(ShowWindow or SetForegroundWindow) using the Process.MainWindowHandle
property, but as I mentioned it's set to 0 when the form is hidden.

Does anyone have any ideas how to proceed with this? The only other
way I thought of doing this was to send a message directly to the
hidden application telling it to make itself visible and restore its
window position. Now comes the second problem...how do I do this? I
don't want to get into sockets, etc. as it is all local to the one
machine. Message queues would be another alternative, but I'd prefer
to use something that doesn't have to be installed separately to a
standard framework installation.

There is a fair chance I'm missing something pretty obvious here, but
please...feel free to point it out. :-)

Thanks in advance,

Neill.


______________________________________________
WORK: N M @ R C S S o f t w a r e . c o . u k
HOME: n e i l l . i m m o r t a l @ B T I n t e r n e t . c o m
WEB: www.neill.immortal.btinternet.com
 
Neill,

While it is true that the value of Process.MainWindowHandle will be 0 for
hidden forms, the window procedure is still processing incoming messages.
Because you don't know the handle of the target window, my suggestion would
be to register a system-wide message and then broadcast this message to
switch to your hidden application.

This requires to resort to platform invoke (PInvoke), but it's not that
complicated. First you need to declare the Windows functions that we are
going to use:

[DllImport("USER32.DLL")]
public static extern int RegisterWindowMessage(String lpString);

[DllImport("USER32.DLL")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool PostMessage(IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg, IntPtr wParam, IntPtr lParam);

Then we declare an integer variable for the message that we are going to
register:

int msg;

In the Form.Load() event we are going to register our custom message.
Subsequent registrations of the same message would return the same value,
and this value will remain registered until the end of the user session.

msg = RegisterWindowMessage("SwitchToMessage");

From the main application we will send this message to the target
application using something like this:

PostMessage((System.IntPtr)HWND_BROADCAST, msg, (System.IntPtr)1,
(System.IntPtr)0);

I'm using the value of wParam (1) to specify the id of the application that
I want to show. This just in case you have more than one application to
show. When using PostMessage with HWND_BROADCAST as target window the
message is posted to all top-level windows in the system, including disabled
or invisible windows. You could also use lParam to pass some other specific
parameters. HWND_BROADCAST is a constant defined as:

public const int HWND_BROADCAST = 0xFFFF;

What is left to do now is to handle this message in your hidden application.
Here you would have to register for the message again in the Form.Load()
event, and then override the Form.WndProc() method like this:

protected override void WndProc(ref Message m)
{
// check for our message
if(m.Msg == msg)
{
// check for proper application id
if(m.WParam == 1)
{
this.Visible=true;
}
}
else
{
// default processing
base.WndProc(ref m);
}
}

That's pretty much all you have to do.

For more information please see the following documents:

Platform Invoke Tutorial
http://msdn.microsoft.com/library/d...us/csref/html/vcwlkplatforminvoketutorial.asp

RegisterWindowMessage Function
http://msdn.microsoft.com/library/d...sageQueuesFunctions/RegisterWindowMessage.asp

PostMessage Function
http://msdn.microsoft.com/library/d...agesandMessageQueuesFunctions/PostMessage.asp

Regards,

Gabriele
 
Hi Gabriele,

Thanks for your excellent reply. I'll give it a try tomorrow.

Neill.

Neill,

While it is true that the value of Process.MainWindowHandle will be 0 for
hidden forms, the window procedure is still processing incoming messages.
Because you don't know the handle of the target window, my suggestion would
be to register a system-wide message and then broadcast this message to
switch to your hidden application.

This requires to resort to platform invoke (PInvoke), but it's not that
complicated. First you need to declare the Windows functions that we are
going to use:

[DllImport("USER32.DLL")]
public static extern int RegisterWindowMessage(String lpString);

[DllImport("USER32.DLL")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool PostMessage(IntPtr hWnd,
[MarshalAs(UnmanagedType.U4)] int Msg, IntPtr wParam, IntPtr lParam);

Then we declare an integer variable for the message that we are going to
register:

int msg;

In the Form.Load() event we are going to register our custom message.
Subsequent registrations of the same message would return the same value,
and this value will remain registered until the end of the user session.

msg = RegisterWindowMessage("SwitchToMessage");

From the main application we will send this message to the target
application using something like this:

PostMessage((System.IntPtr)HWND_BROADCAST, msg, (System.IntPtr)1,
(System.IntPtr)0);

I'm using the value of wParam (1) to specify the id of the application that
I want to show. This just in case you have more than one application to
show. When using PostMessage with HWND_BROADCAST as target window the
message is posted to all top-level windows in the system, including disabled
or invisible windows. You could also use lParam to pass some other specific
parameters. HWND_BROADCAST is a constant defined as:

public const int HWND_BROADCAST = 0xFFFF;

What is left to do now is to handle this message in your hidden application.
Here you would have to register for the message again in the Form.Load()
event, and then override the Form.WndProc() method like this:

protected override void WndProc(ref Message m)
{
// check for our message
if(m.Msg == msg)
{
// check for proper application id
if(m.WParam == 1)
{
this.Visible=true;
}
}
else
{
// default processing
base.WndProc(ref m);
}
}

That's pretty much all you have to do.

For more information please see the following documents:

Platform Invoke Tutorial
http://msdn.microsoft.com/library/d...us/csref/html/vcwlkplatforminvoketutorial.asp

RegisterWindowMessage Function
http://msdn.microsoft.com/library/d...sageQueuesFunctions/RegisterWindowMessage.asp

PostMessage Function
http://msdn.microsoft.com/library/d...agesandMessageQueuesFunctions/PostMessage.asp

Regards,

Gabriele

N M said:
Hi all,

I've been scratching my head (to the bone) try to find a way of
switching from one .Net application to another. ie. I click a button
on a controller application and the other one is brought to the front.

I even have a Process object pointing to the application I want to
activate, but I can't seem to find any way of using this.

The purpose of the controller application is to provide a single
interface to launch/terminate/switch to a suite of programs without
having loads of applications in either the task bar or the system
tray.

Herein lies the problem. In order to hide the application when it is
minimised, I have to either sets its ShowInTaskBar property to false
or just hide it. The trouble is, when you do this you lose the handle
as there isn't a window anymore. I tried using the API calls
(ShowWindow or SetForegroundWindow) using the Process.MainWindowHandle
property, but as I mentioned it's set to 0 when the form is hidden.

Does anyone have any ideas how to proceed with this? The only other
way I thought of doing this was to send a message directly to the
hidden application telling it to make itself visible and restore its
window position. Now comes the second problem...how do I do this? I
don't want to get into sockets, etc. as it is all local to the one
machine. Message queues would be another alternative, but I'd prefer
to use something that doesn't have to be installed separately to a
standard framework installation.

There is a fair chance I'm missing something pretty obvious here, but
please...feel free to point it out. :-)

Thanks in advance,

Neill.


______________________________________________
WORK: N M @ R C S S o f t w a r e . c o . u k
HOME: n e i l l . i m m o r t a l @ B T I n t e r n e t . c o m
WEB: www.neill.immortal.btinternet.com

______________________________________________
WORK: n e i l l @ f u z z y g o a t . c o m
WEB: www.fuzzygoat.com
 
Back
Top