windows 有没有可靠的方法来使用 C# 激活/设置窗口焦点?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2671669/
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-09-15 14:18:36  来源:igfitidea点击:

Is there a reliable way to activate / set focus to a window using C#?

c#windowsfocus

提问by gtaborga

I'm trying to find a reliable way to activate / set focus to a window of an external application using C#. Currently I'm attempting to achieve this using the following Windows API calls:

我试图找到一种可靠的方法来激活/设置焦点到使用 C# 的外部应用程序的窗口。目前我正在尝试使用以下 Windows API 调用来实现这一点:

SetActiveWindow(handle);
SwitchToThisWindow(handle, true);

Previously I also had ShowWindow(handle, SW_SHOWMAXIMIZED);executing before the other 2, but removed it because it was causing strange behavior.

以前我也曾ShowWindow(handle, SW_SHOWMAXIMIZED);在其他 2 个之前执行过,但将其删除,因为它导致了奇怪的行为。

The problem I'm having with my current implementation is that occasionally the focus will not be set correctly. The window will become visible but the top part of it will still appear grayed out as if it wasn't in focus.

我目前的实现遇到的问题是,有时焦点设置不正确。窗口将变得可见,但它的顶部仍然会显示为灰色,好像它没有聚焦。

Is there a way to reliably do this which works 100% of the time, or is the inconsistent behavior a side-effect I can't escape? Please let me know if you have any suggestions or implementations that always work.

有没有办法可靠地做到这一点,在 100% 的时间里都有效,或者不一致的行为是我无法逃避的副作用?如果您有任何始终有效的建议或实现,请告诉我。

采纳答案by Logan Capaldo

You need to use AttachThreadInput

你需要使用 AttachThreadInput

Windows created in different threads typically process input independently of each other. That is, they have their own input states (focus, active, capture windows, key state, queue status, and so on), and they are not synchronized with the input processing of other threads. By using the AttachThreadInput function, a thread can attach its input processing to another thread. This also allows threads to share their input states, so they can call the SetFocus function to set the keyboard focus to a window of a different thread. This also allows threads to get key-state information. These capabilities are not generally possible.

在不同线程中创建的 Windows 通常相互独立地处理输入。也就是说,它们有自己的输入状态(焦点、活动、捕获窗口、关键状态、队列状态等),它们不与其他线程的输入处理同步。通过使用 AttachThreadInput 函数,一个线程可以将其输入处理附加到另一个线程。这也允许线程共享它们的输入状态,因此它们可以调用 SetFocus 函数将键盘焦点设置到不同线程的窗口。这也允许线程获取关键状态信息。这些能力通常是不可能的。

I am not sure of the ramifications of using this API from (presumably) Windows Forms. That said, I've used it in C++ to get this effect. Code would be something like as follows:

我不确定从(大概)Windows Forms 使用这个 API 的后果。也就是说,我已经在 C++ 中使用它来获得这种效果。代码如下所示:

     DWORD currentThreadId = GetCurrentThreadId();
     DWORD otherThreadId = GetWindowThreadProcessId(targetHwnd, NULL);
     if( otherThreadId == 0 ) return 1;
     if( otherThreadId != currentThreadId )
     {
       AttachThreadInput(currentThreadId, otherThreadId, TRUE);
     }

     SetActiveWindow(targetHwnd);

     if( otherThreadId != currentThreadId )
     {
       AttachThreadInput(currentThreadId, otherThreadId, FALSE);
     }

targetHwndbeing the HWNDof the window you want to set focus to. I assume you can work out the P/Invoke signature(s) since you're already using native APIs.

targetHwndHWND您要设置焦点的窗口的 。我假设您可以计算出 P/Invoke 签名,因为您已经在使用本机 API。

回答by Guillaume Massé

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetForegroundWindow(IntPtr hWnd);

This one worked for me

这个对我有用

回答by Shimmy Weitzhandler

If it's all internal in your application then you can get the parent window or that window, and in this way activate it (vb sorry):

如果它全部在您的应用程序内部,那么您可以获得父窗口或该窗口,并以这种方式激活它(对不起):

Public Class Form1 : Inherits Form

    Protected Overrides Sub OnLoad(e As EventArgs)
        Dim form2 As New Form2
        form2.Show()
    End Sub
End Class

Class Form2 : Inherits Form

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        Me.Owner.Activate()
    End Sub
End Class

回答by user10373476

        hwnd_WhoRecvFocus.ShowWindow( SW_MINIMIZE )
        hwnd_WhoRecvFocus.ShowWindow( SW_RESTORE )