C# 通过P/Invoke调用GetGUIThreadInfo

C# 通过P/Invoke调用GetGUIThreadInfo,c#,pinvoke,C#,Pinvoke,我想在另一个进程中将键盘输入发送到窗口,而不将该窗口置于前台。我可以使用PostMessage来伪造WM_KEYDOWN和WM_keydup;我只需要知道哪个窗口句柄应该接收键盘输入——例如,类似于,但对于另一个非活动应用程序 该API看起来很有前途——它为另一个应用程序返回hwndFocus。但在我的64位操作系统上,我没能从C#上运行它。我从中复制了(然后进一步调整)声明,但我得到的只是一个通用错误代码(更多细节见下文) 我在调用GetGuitThreadInfo之前设置了cbSize,因此

我想在另一个进程中将键盘输入发送到窗口,而不将该窗口置于前台。我可以使用
PostMessage
来伪造
WM_KEYDOWN
WM_keydup
;我只需要知道哪个窗口句柄应该接收键盘输入——例如,类似于,但对于另一个非活动应用程序

该API看起来很有前途——它为另一个应用程序返回
hwndFocus
。但在我的64位操作系统上,我没能从C#上运行它。我从中复制了(然后进一步调整)声明,但我得到的只是一个通用错误代码(更多细节见下文)

我在调用GetGuitThreadInfo之前设置了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) { var threadId = GetWindowThreadProcessId(window, IntPtr.Zero); var info = new GuiThreadInfo(); info.cbSize = Marshal.SizeOf(info); if (!GetGUIThreadInfo(threadId, ref info)) throw new Win32Exception(); return info.hwndFocus; } [StructLayout(LayoutKind.Sequential)] 内部结构矩形 { 公共int左; 公共int Top; 公共权利; 公共int底部; } [StructLayout(LayoutKind.Sequential)] 内部类信息 { 公共机构的规模; 国旗; 公共IntPtr hwndActive; 公共IntPtr hwndFocus; 公共IntPtr hwndCapture; 公共IntPtr hwndMenuOwner; 公共IntPtr hwndMoveSize; 公共IntPtr hwndCaret; 公共矩形插入符号; } [DllImport(“user32.dll”)] 内部静态外部单元GetWindowThreadProcessId(IntPtr hWnd,IntPtr ProcessId); [DllImport(“user32.dll”,SetLastError=true)] 内部静态外部bool GetGUIThreadInfo(uint-idThread,ref-GuiThreadInfo-lpgui); IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr窗口) { var threadId=GetWindowThreadProcessId(窗口,IntPtr.Zero); var info=new-GuiThreadInfo(); info.cbSize=Marshal.SizeOf(info); 如果(!GetGuitThreadInfo(线程ID,参考信息)) 抛出新的Win32Exception(); 返回info.hwndFocus; }
窗口
是有效的窗口句柄
GetWindowThreadProcessId
返回非零线程句柄。但是对
GetGUIThreadInfo
的调用总是返回
false
,异常消息总是“参数不正确”

万一问题是
GetGUIThreadInfo
没有64位版本,我尝试将
GuiThreadInfo
声明中的所有8字节
IntPtr
s更改为4字节
int
s,但仍然得到相同的错误


有人在Win64上有可用的
GetGUIThreadInfo
C#示例吗?或者,是否有其他方法可以找到另一个应用程序中的聚焦子窗口句柄,而不激活该应用程序?

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

Ouch。你说得对,我真不敢相信我错过了。礼仪要点:这解决了眼前的问题,但随后又出现了另一个问题;所以我的最终目标“在其他过程中集中精力”仍然是开放的。我应该编辑这个问题,还是接受这个答案,然后写一个新的问题?在这种情况下,这个问题实际上是关于pInvoking GetGUIThreadInfo的,所以你可能应该投票认为它有帮助,并将其标记为答案。您可能还希望编辑标题以更狭义地描述此问题。然后添加一个关于更一般问题的新问题,包括……您的基本需求是什么以及您迄今为止尝试了什么。一般来说,你应该编辑一个问题来增加信息或清晰,而不是改变被问的内容。