tags:

views:

967

answers:

4

I have an application which may only have one instance of itself open at a time. To enforce this, I use this code:

        System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses();
        System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
        foreach (System.Diagnostics.Process p in myProcesses)
        {
            if (p.ProcessName == me.ProcessName)
                if (p.Id != me.Id)
                {
                    //if already running, abort this copy.
                    return;
                }
        }
        //launch the application.
        //...

It works fine. I would also like it to be able to focus the form of the already-running copy. That is, before returning, I want to bring the other instance of this application into the foreground.

How do I do that?

Re: SetForeGroundWindow:

SetForeGroundWindow works, to a point:

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern bool SetForegroundWindow(IntPtr hWnd); 

    //...
                if (p.Id != me.Id)
                {
                    //if already running, focus it, and then abort this copy.
                    SetForegroundWindow(p.MainWindowHandle);
                    return;
                }
    //...

This does bring the window to the foreground if it is not minimized. Awesome. If the window IS minimized, however, it remains minimized.

It needs to un-minimize.

Solution via SwitchToThisWindow (Works!):

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

    [STAThread]
    static void Main()
    {
        System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
        System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcessesByName(me.ProcessName);
        foreach (System.Diagnostics.Process p in myProcesses)
        {
            if (p.Id != me.Id)
            {
                SwitchToThisWindow(p.MainWindowHandle, true);
                return;
            }
        }
        //now go ahead and start our application ;-)
+1  A: 

I believe you will want to use SetForegroundWindow

MSDN Example

cmsjr
A: 

Can you grab MainWindowHandle property of the Process object and send it a WM_USER message that you can interpret as "some other instance wants to bring me to the front".

plinth
Could do that, seems ugly though. It might be a good alternative if SetForegroundWindow doesn't pan out.
Blinky
A: 

Complete Side Note...

You can use

Process.GetProcessesByName(me.ProcessName)

instead of looping over all the processes running on the system...

UPDATE

PInvoke Rules for this sort of thing...

Jason Punyon
+2  A: 

I had the same problem and SwitchToThisWindow() worked the best for me. The only limitation is that you must have XP sp1 installed. I played with SetForegroundWindow, ShowWindow, and they both had problems pulling the window into view.

scottm