我想将键盘输入发送到另一个进程中的窗口,而不将该窗口带到前台.我可以PostMessage
用来伪造WM_KEYDOWN
和WM_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) { 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; }
window
是一个有效的窗口句柄; GetWindowThreadProcessId
返回非零线程句柄.但是对GetGUIThreadInfo
always 的调用总是返回false
,而异常消息总是"参数不正确".
为了防止问题是GetGUIThreadInfo
某种程度上没有64位版本,我尝试将声明中的所有8字节IntPtr
s 更改GuiThreadInfo
为4字节int
s,但我仍然遇到相同的错误.
有没有人GetGUIThreadInfo
在Win64上有一个有效的C#样本?或者,是否有另一种方法可以找到聚焦的子窗口句柄在另一个应用程序中的位置,而不会使该应用程序处于活动状态?
我没有仔细看过它,但有一件事情跳了出来.在您的GetGUIThreadInfo调用中,您通过ref传递GUIThreadInfo结构,但您已将其定义为类,因此您通过ref发送引用,换句话说,指向指针的指针.将GUIThreadInfo更改为结构或删除参数上的ref并添加[In,Out]属性.