Есть ли надежный способ активировать / установить фокус на окно с помощью 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