Есть ли надежный способ активировать / установить фокус на окно с помощью C#?

Я пытаюсь найти надежный способ активировать / установить фокус на окно внешнего приложения с использованием C#. В настоящее время я пытаюсь достичь этого, используя следующие вызовы Windows API:

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

раньше у меня тоже было ShowWindow(handle, SW_SHOWMAXIMIZED); выполнение перед другими 2, но удалил его, потому что он вызывал странное поведение.

проблема, с которой я сталкиваюсь с моей текущей реализацией, заключается в том, что иногда фокус не будет установлен правильно. Окно станет видимая, но верхняя часть ее по-прежнему будет казаться серой, как будто она не была в фокусе.

есть ли способ надежно сделать это, который работает 100% времени, или несогласованный побочный эффект я не могу сбежать? Пожалуйста, дайте мне знать, если у вас есть какие-либо предложения или реализации, которые всегда работают.

4 ответов


вам нужно использовать AttachThreadInput

окна, созданные в разных потоках, обычно обрабатывают ввод независимо друг от друга. То есть они имеют свои собственные состояния ввода (фокус, активный, окна захвата, состояние ключа, состояние очереди и т. д.), И они не синхронизируются с обработкой ввода других потоков. С помощью функции AttachThreadInput поток может присоединить свою входную обработку к другому потоку. Это также позволяет потокам делиться своими состояния ввода, поэтому они могут вызвать функцию SetFocus, чтобы установить фокус клавиатуры на окно другого потока. Это также позволяет потокам получать информацию о состоянии ключа. Такие возможности, как правило, невозможны.

Я не уверен в последствиях использования этого API из (предположительно) Windows Forms. Тем не менее, я использовал его в 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);
     }

targetHwnd являясь HWND окна хотите установить фокус. Я предполагаю, что вы можете разработать подпись(ы) P/Invoke, так как вы уже используете собственные API.


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

это сработало для меня


Если это все внутреннее в вашем приложении, вы можете получить родительское окно или это окно и таким образом активировать его (VB извините):

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

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