通过P/Invoke调用GetGUIThreadInfo函数

14
我想在不将窗口置于前台的情况下向另一个进程中的窗口发送键盘输入。我可以使用PostMessage来模拟WM_KEYDOWNWM_KEYUP,唯一需要知道的是哪个窗口句柄应该接收键盘输入,即类似于GetFocus,但是针对另一个非活动应用程序。 GetGUIThreadInfo API看起来很有前途 -- 它返回另一个应用程序的hwndFocus。但是,在我的64位操作系统上,我尝试从C#中使用它却没有成功。我已经从pinvoke.net复制了声明,并进行了进一步修改,但我得到的仅仅是一个通用错误码(详细信息如下)。
在调用GetGUIThreadInfo之前,我设置了cbSize,因此我避免了最明显的潜在问题。
我正在运行64位Vista,因此我不知道问题是我没有正确使用API还是它在64位上的工作方式不同 -- 我还没有找到一个代码示例,明确说明它在Win64上成功运行。
这是示例代码。我正在使用建议使用的GetWindowThreadProcessId,因此我不认为问题与混合线程ID和线程句柄有关:
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}
[StructLayout(LayoutKind.Sequential)] internal class GuiThreadInfo { public int cbSize; public uint flags; public IntPtr hwndActive; public IntPtr hwndFocus; public IntPtr hwndCapture; public IntPtr hwndMenuOwner; public IntPtr hwndMoveSize; public IntPtr hwndCaret;
public Rect rcCaret;
}
[DllImport("user32.dll")] internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("user32.dll", SetLastError = true)] internal static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui);
IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr window) { //获取窗口线程ID var threadId = GetWindowThreadProcessId(window, IntPtr.Zero); //构造用于存储GUI信息的结构体 var info = new GuiThreadInfo(); info.cbSize = Marshal.SizeOf(info); //获取线程中GUI信息,如果返回false则抛出Win32异常 if (!GetGUIThreadInfo(threadId, ref info)) throw new Win32Exception(); //返回位于窗口上方的子窗口句柄 return info.hwndFocus; }

window 是一个有效的窗口句柄;GetWindowThreadProcessId 返回一个非零的线程句柄。但是调用 GetGUIThreadInfo 始终返回 false,并显示 "The parameter is incorrect" 异常消息。

为了排除问题可能是 GetGUIThreadInfo 没有 64 位版本的情况,我尝试将 GuiThreadInfo 中所有 8 字节的 IntPtr 更改为 4 字节的 int,但仍然得到相同的错误。

有没有人有 Win64 上 GetGUIThreadInfo 的 C# 示例?或者,是否有另一种方法可以找到另一个应用程序中的焦点子窗口句柄,而不使该应用程序处于活动状态?

1个回答

6

我没有仔细研究,但有一件事情很明显。在您的GetGUIThreadInfo调用中,您通过引用传递GUIThreadInfo结构,但您已将其定义为类,因此您正在发送一个引用by ref,换句话说是指向指针的指针。要么将您的GUIThreadInfo更改为结构体,要么删除参数上的ref并添加[In,Out]属性。


1
哎呀,你说得对 -- 我简直不敢相信我居然错过了那个。关于礼仪方面:这解决了眼前的问题,但接着又出现了另一个问题;所以我的最终目标“在其他进程中获取聚焦句柄”仍然没有解决。我应该编辑这个问题,还是接受这个答案然后写一个新问题? - Joe White
在这种情况下,问题实际上是关于pInvoking GetGUIThreadInfo的,因此您应该将其投票为有帮助并将其标记为答案。您可能还想编辑标题以更具体地描述此问题。然后添加一个新问题,包括... - Stephen Martin
你需要明确自己的基本需求以及迄今所做的尝试。通常来说,编辑问题应该是为了增加信息或阐明问题,而不是改变问题的实质。 - Stephen Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接