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的,所以你可能应该投票认为它有帮助,并将其标记为答案。您可能还希望编辑标题以更狭义地描述此问题。然后添加一个关于更一般问题的新问题,包括……您的基本需求是什么以及您迄今为止尝试了什么。一般来说,你应该编辑一个问题来增加信息或清晰,而不是改变被问的内容。