Introduction
This article will describe how you can retrieve the unique handle of any focusable control in any Windows application by simply focusing it. We will do this through a series of P/Invokes to the Win32 API in user32.dll.
Background
People using the Win32 API function GetFocus
may have noticed that it will only return the handle (hWnd
) of controls in your own application, and if you try focusing in another process, you will get NULL
. This is because GetFocus
only returns the window with the keyboard focus for the current thread's message queue. And, since our application is not in the same thread, you will get nothing.
Using the code
To get the currently focused control hWnd
in another process, we can attach our thread's message queue to a window in another thread, using the AttachThreadInput
function.
This is how it's done:
- Use the
GetForegroundWindow
function to get the window with which the user is currently working.
- Use the
GetWindowThreadProcessId
function to get the ID of both this window and yours.
- Use the
AttachThreadInput
function to temporarily associate your thread's message queue with the thread owning the other window.
- Use the
GetFocus
function to get the hWnd
!
- Use the
AttachThreadInput
function again to disconnect from the other thread.
using System.Runtime.InteropServices;
public partial class FormMain : Form
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
static extern IntPtr AttachThreadInput(IntPtr idAttach,
IntPtr idAttachTo, bool fAttach);
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
public FormMain()
{
InitializeComponent();
}
private void timerUpdate_Tick(object sender, EventArgs e)
{
labelHandle.Text = "hWnd: " +
FocusedControlInActiveWindow().ToString();
}
private IntPtr FocusedControlInActiveWindow()
{
IntPtr activeWindowHandle = GetForegroundWindow();
IntPtr activeWindowThread =
GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
IntPtr thisWindowThread = GetWindowThreadProcessId(this.Handle, IntPtr.Zero);
AttachThreadInput(activeWindowThread, thisWindowThread, true);
IntPtr focusedControlHandle = GetFocus();
AttachThreadInput(activeWindowThread, thisWindowThread, false);
return focusedControlHandle;
}
}
Requirements for the code, which can be done with the Visual Studio designer:
- Add a timer with the name
timerUpdate
and add the timerUpdate_Tick
method to the Tick
event. Set Interval
to 100 and Enabled
to true
.
- Add a
Label
to the form with the name labelHandle
.
- Set
FormMain
's TopMost
property to true
.
History
- 1.0 (1 April 2009) - Initial release.