How do I focus a foreign window?

2020-02-03 04:27发布

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 ;-)

标签: c# .net focus
6条回答
Explosion°爆炸
2楼-- · 2020-02-03 04:46

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.

查看更多
Lonely孤独者°
3楼-- · 2020-02-03 04:57

Same as OP, I found that SetForegroundWindow alone wasn't enough when the window was minimized. Since I didn't want to use SwitchToThisWindow, I chose ShowWindow followed by SetForegroundWindow.

Works well for me!

private const SW_SHOWNORMAL = 1

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As integer) As Boolean
End Function

<DllImport("user32.dll", SetLastError:=True)> _
Private Function SetForegroundWindow(ByVal hwnd As IntPtr) As Boolean
End Function

Sub SetForeground()
    Dim processes As Process() = Process.GetProcessesByName("myprocess")

    For Each p as Process in processes
        ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL)
        SetForegroundWindow(p.MainWindowHandle)
    Next
End Sub
查看更多
够拽才男人
4楼-- · 2020-02-03 04:57

I believe you will want to use SetForegroundWindow

MSDN Example

查看更多
【Aperson】
5楼-- · 2020-02-03 04:59

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".

查看更多
劳资没心,怎么记你
6楼-- · 2020-02-03 05:05

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...

查看更多
兄弟一词,经得起流年.
7楼-- · 2020-02-03 05:08

C# equivalent of Tom Juergens's answer. Works like a charm for me.

    private const  int SW_SHOWNORMAL = 1;

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);


    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool SetForegroundWindow(IntPtr hwnd);

    public void SetForeground()
    {
        Process[] processes = Process.GetProcessesByName("process name");

        foreach (Process p in processes) {
            ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL);
            SetForegroundWindow(p.MainWindowHandle);
        }
    }
查看更多
登录 后发表回答