Reputation: 833
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:
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.
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.
Upvotes: 9
Views: 15751
Reputation: 1
hwnd_WhoRecvFocus.ShowWindow( SW_MINIMIZE )
hwnd_WhoRecvFocus.ShowWindow( SW_RESTORE )
Upvotes: 0
Reputation: 8064
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
This one worked for me
Upvotes: 5
Reputation: 40336
You need to use 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.
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:
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
being the HWND
of 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.
Upvotes: 10
Reputation: 104692
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
Upvotes: 1