【发布时间】:2010-10-17 17:11:55
【问题描述】:
我想将键盘输入发送到另一个进程中的窗口,而不是将该窗口置于前台。我可以使用PostMessage 来伪造WM_KEYDOWN 和WM_KEYUP;我只需要知道哪个窗口句柄应该接收键盘输入——比如GetFocus,但是对于另一个非活动应用程序。
GetGUIThreadInfo API 看起来很有前景——它为另一个应用返回一个hwndFocus。但是我没有运气让它在我的 64 位操作系统上通过 C# 工作。我已经从pinvoke.net 复制(然后进一步调整)了声明,但我得到的只是一个通用错误代码(下面有更多详细信息)。
我在调用 GetGUIThreadInfo 之前设置 cbSize,因此我避免了最明显的潜在问题。
我正在运行 64 位 Vista,所以我不知道问题是我没有正确使用 API,还是它在 64 位中的工作方式不同——我还没有找到代码特别说明它在 Win64 中成功运行的示例。
这里是示例代码。我正在使用 GetWindowThreadProcessId as recommended,所以我认为问题与混合线程 ID 和线程句柄无关:
[StructLayout(LayoutKind.Sequential)]
内部结构 Rect
{
公共 int 左;
公共int顶部;
公共 int 权利;
公共 int 底部;
}
[StructLayout(LayoutKind.Sequential)]
内部类 GuiThreadInfo
{
公共 int cbSize;
公共单位标志;
公共 IntPtr hwndActive;
公共 IntPtr hwndFocus;
公共 IntPtr hwndCapture;
公共 IntPtr hwndMenuOwner;
公共 IntPtr hwndMoveSize;
公共 IntPtr hwndCaret;
公共矩形 rcCaret;
}
[DllImport("user32.dll")]
内部静态外部 uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll", SetLastError = true)]
内部静态 extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui);
IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr 窗口)
{
var threadId = GetWindowThreadProcessId(window, IntPtr.Zero);
var info = new GuiThreadInfo();
info.cbSize = Marshal.SizeOf(info);
if (!GetGUIThreadInfo(threadId, ref info))
抛出新的 Win32Exception();
返回 info.hwndFocus;
}
window 是一个有效的窗口句柄; GetWindowThreadProcessId 返回一个非零线程句柄。但是调用GetGUIThreadInfo总是返回false,异常信息总是“参数不正确”。
以防万一问题是 GetGUIThreadInfo 不知何故没有 64 位版本,我尝试将 GuiThreadInfo 声明中的所有 8 字节 IntPtrs 更改为 4 字节 ints ,但我仍然遇到同样的错误。
有没有人在 Win64 上有一个可用的 GetGUIThreadInfo 的 C# 示例?或者,是否有另一种方法可以在不激活该应用的情况下找到另一个应用中的焦点子窗口句柄?
【问题讨论】: