通过 P/Invoke 调用 GetGUIThreadInfo

Posted

技术标签:

【中文标题】通过 P/Invoke 调用 GetGUIThreadInfo【英文标题】:Calling GetGUIThreadInfo via P/Invoke 【发布时间】:2010-10-17 17:11:55 【问题描述】:

我想将键盘输入发送到另一个进程中的窗口,而不是将该窗口置于前台。我可以使用PostMessage 来伪造WM_KEYDOWNWM_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# 示例?或者,是否有另一种方法可以在不激活该应用的情况下找到另一个应用中的焦点子窗口句柄?

【问题讨论】:

【参考方案1】:

我没有仔细看它,但有一件事跳出来了。在您的 GetGUIThreadInfo 调用中,您通过 ref 传递 GUIThreadInfo 结构,但您已将其定义为一个类,因此您通过 ref 发送引用,换句话说,是指向指针的指针。将您的 GUIThreadInfo 更改为结构或删除参数上的 ref 并添加 [In, Out] 属性。

【讨论】:

哎哟。你是对的——我不敢相信我错过了。礼仪要点:这解决了眼前的问题,但随后又出现了另一个问题;所以我“在其他过程中获得重点处理”的最终目标仍然是开放的。我应该编辑这个问题,还是接受这个答案然后写一个新问题? 在这种情况下,问题实际上与 pInvoking GetGUIThreadInfo 有关,因此您可能应该将其投票为有帮助并将其标记为答案。您可能还想编辑标题以更严格地描述这个问题。然后添加一个关于更一般问题的新问题,包括什么... ...您的基本要求是以及您到目前为止所尝试的内容。通常,您应该编辑问题以添加信息或明确性,而不是更改所问的内容。

以上是关于通过 P/Invoke 调用 GetGUIThreadInfo的主要内容,如果未能解决你的问题,请参考以下文章

P/Invoke之C#调用动态链接库DLL

[.NET] 平台调用(P/Invoke) 与 DllImport 使用的相关讲解与注意事项,

[.NET] 平台调用(P/Invoke) 与 DllImport 使用的相关讲解与注意事项,

与普通的 p/Invoke 调用相比,使用不安全的 P/Invoke 调用是不是有性能优势?

通过 P/Invoke 将 MFC CArray 编组为 C#

使用 P/Invoke 调用 dll 时,为啥 LoadLibrary 在某些机器上会失败?