我想从另一个窗口的按钮正确接收消息。也许我需要使用钩子,但我不确定这件事(这就是我要问的原因)。所以我想做的这个(但它无法正常工作):
void CaptureTextWindow::Execute()
{
BOOL bRet;
vector<string> TextInWindow( ExecuteCapturingWindow() );
while( !( bRet = GetMessage( NULL, hWndBut, 0 , 0 ) ) )
{
SaveResultToFile( "Message.txt" );
}
}
所以这就是我想要的,如果按下来自另一个窗口(进程)的按钮,该程序应该将某些东西保存到文件中,否则它应该等待。
答案 0 :(得分:3)
要在另一个进程中检测按钮按下,您必须挂钩该进程。这样做有四种选择:
使用SetWindowsHookEx()
在目标进程中安装WH_CALLWNDPROC
或WH_GETMESSAGE
挂钩,以捕获发送到按钮父窗口的WM_COMMAND/BN_CLICKED
消息单击按钮。该消息标识所单击按钮的HWND
和ID。钩子必须在DLL中实现,以便它可以注入另一个进程。
单击按钮时使用SetWinEventHook()
来捕获EVENT_OBJECT_INVOKED
事件。钩子回调标识了被点击的按钮的HWND
和ID。钩子应该在DLL中实现,因此可以将其注入目标进程以获得更好的性能,但不是必需。如果您不使用DLL,则挂钩线程必须有一个消息循环来接收事件,因为它们必须跨越进程边界传递。
使用SetWindowsHookEx()
或CreateRemoteThread()
将代码注入目标进程,然后让代码使用SetWindowsLongPtr(GWL_WNDPROC)
或SetWindowSubclass()
对按钮的父窗口进行子类化,以便捕获发送到该父窗口的WM_COMMAND/BN_CLICKED
消息。
使用UI Automation。使用CoCreateInstance()
函数创建IUIAutomation
接口的实例,然后使用IUIAutomation::ElementFromHandle()
方法从按钮的HWND
获取IUIAutomationElement
接口(或获取按钮的IUIAutomationElement
界面通过其他方式),然后使用IUIAutomation::AddAutomationEventHandler()
方法订阅该按钮的UIA_Invoke_InvokedEventId
事件。
如果您拥有目标按钮的HWND
,则可以使用GetWindowThreadProcessId()
来检索按钮的进程ID和线程ID。您将需要按钮的父窗口HWND
(如果需要,您可以使用GetParent()
获取)以使用SetWindowsLongPtr(GWL_WNDPROC)
或SetWindowSubclass()
。
SetWindowsHookEx()
和SetWinEventHook()
允许您指定要挂钩的特定线程ID(在SetWinEventHook()
的情况下也指定特定的进程ID),这样您就可以最大限度地减少开销中使用的开销挂钩。 CreateRemoteThread()
需要目标流程句柄,您可以使用流程ID通过OpenProcess()
获取该句柄。
所以,正如你所看到的,你所要求的并不是微不足道的。在我看来(不是确定的),在编码方面,从最简单到最难的技术顺序是:
SetWinEventHook()
没有DLL(但会以影响性能为代价)。
SetWindowsHookEx()
因为额外的注入代码和子类化