我想在不将窗口置于前台的情况下向另一个进程中的窗口发送键盘输入。我可以使用
在调用GetGUIThreadInfo之前,我设置了cbSize,因此我避免了最明显的潜在问题。
我正在运行64位Vista,因此我不知道问题是我没有正确使用API还是它在64位上的工作方式不同 -- 我还没有找到一个代码示例,明确说明它在Win64上成功运行。
这是示例代码。我正在使用建议使用的GetWindowThreadProcessId,因此我不认为问题与混合线程ID和线程句柄有关:
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) { //获取窗口线程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# 示例?或者,是否有另一种方法可以找到另一个应用程序中的焦点子窗口句柄,而不使该应用程序处于活动状态?