其他进程中的焦点控件
检索其他应用程序中具有焦点的控件的 hWnd。
引言
本文将介绍如何通过简单地将焦点设置在其上,来检索任何 Windows 应用程序中任何可聚焦控件的唯一句柄。我们将通过一系列 P/Invoke 调用到 user32.dll 中的 Win32 API 来实现这一点。
背景
使用 Win32 API 函数 GetFocus
的人可能已经注意到,它只会返回自身应用程序中控件的句柄(hWnd
),并且如果您尝试在另一个进程中设置焦点,您将得到 NULL
。这是因为 GetFocus
仅返回当前线程消息队列中具有键盘焦点的窗口。由于我们的应用程序不在同一个线程中,您将无法获得任何信息。
使用代码
要获取另一个进程中当前具有焦点的控件的 hWnd
,我们可以使用 AttachThreadInput
函数将我们的线程消息队列附加到另一个线程中的窗口。
操作方法如下:
- 使用
GetForegroundWindow
函数获取用户当前正在使用的窗口。 - 使用
GetWindowThreadProcessId
函数获取该窗口和您的窗口的 ID。 - 使用
AttachThreadInput
函数临时将您的线程消息队列与拥有另一个窗口的线程关联起来。 - 使用
GetFocus
函数获取hWnd
! - 再次使用
AttachThreadInput
函数断开与另一个线程的连接。
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;
}
}
代码要求,可以使用 Visual Studio 设计器完成
- 添加一个名为
timerUpdate
的计时器,并将timerUpdate_Tick
方法添加到Tick
事件中。将Interval
设置为 100,将Enabled
设置为true
。 - 向窗体添加一个名为
labelHandle
的Label
。 - 将
FormMain
的TopMost
属性设置为true
。
历史
- 1.0 (2009 年 4 月 1 日) - 初始版本。