C# 如何聚焦外窗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/444430/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 03:36:09  来源:igfitidea点击:

How do I focus a foreign window?

c#.netfocus

提问by Jude Allred

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:

SetForeGroundWindow works, to a point:

SetForeGroundWindow 在某种程度上起作用:

    [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!):

通过 SwitchToThisWindow 的解决方案(有效!):

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

采纳答案by scottm

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.

我遇到了同样的问题,SwitchToThisWindow()对我来说效果最好。唯一的限制是您必须安装 XP sp1。我玩过 SetForegroundWindow、ShowWindow,它们都在将窗口拉入视图中时遇到了问题。

回答by cmsjr

I believe you will want to use SetForegroundWindow

我相信你会想要使用SetForegroundWindow

MSDN Example

MSDN 示例

回答by plinth

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

您能否获取 Process 对象的 MainWindowHandle 属性并向其发送 WM_USER 消息,您可以将其解释为“其他一些实例想要将我带到前面”。

回答by Jason Punyon

Complete Side Note...

完整的边注...

You can use

您可以使用

Process.GetProcessesByName(me.ProcessName) 

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

而不是遍历系统上运行的所有进程......

UPDATE

更新

PInvokeRules for this sort of thing...

这类事情的PInvoke规则......

回答by Tom Juergens

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

与 OP 相同,我发现SetForegroundWindow当窗口最小化时,仅靠它是不够的。由于我不想使用SwitchToThisWindow,我选择ShowWindowSetForegroundWindow

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

回答by Nigrimmist

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

C# 相当于 Tom Juergens 的回答。对我来说就像一种魅力。

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