正确接收来自按钮的消息

时间:2013-12-12 19:32:09

标签: c++ winapi

我想从另一个窗口的按钮正确接收消息。也许我需要使用钩子,但我不确定这件事(这就是我要问的原因)。所以我想做的这个(但它无法正常工作):

void CaptureTextWindow::Execute()
{
    BOOL bRet;
    vector<string> TextInWindow( ExecuteCapturingWindow() );
    while( !( bRet = GetMessage( NULL, hWndBut, 0 , 0 ) ) )
    {
        SaveResultToFile( "Message.txt" );
    }
}

所以这就是我想要的,如果按下来自另一个窗口(进程)的按钮,该程序应该将某些东西保存到文件中,否则它应该等待。

1 个答案:

答案 0 :(得分:3)

要在另一个进程中检测按钮按下,您必须挂钩该进程。这样做有四种选择:

  1. 使用SetWindowsHookEx()在目标进程中安装WH_CALLWNDPROCWH_GETMESSAGE挂钩,以捕获发送到按钮父窗口的WM_COMMAND/BN_CLICKED消息单击按钮。该消息标识所单击按钮的HWND和ID。钩子必须在DLL中实现,以便它可以注入另一个进程。

  2. 单击按钮时使用SetWinEventHook()来捕获EVENT_OBJECT_INVOKED事件。钩子回调标识了被点击的按钮的HWND和ID。钩子应该在DLL中实现,因此可以将其注入目标进程以获得更好的性能,但不是必需。如果您不使用DLL,则挂钩线程必须有一个消息循环来接收事件,因为它们必须跨越进程边界传递。

  3. 使用SetWindowsHookEx()CreateRemoteThread()将代码注入目标进程,然后让代码使用SetWindowsLongPtr(GWL_WNDPROC)SetWindowSubclass()对按钮的父窗口进行子类化,以便捕获发送到该父窗口的WM_COMMAND/BN_CLICKED消息。

  4. 使用UI Automation。使用CoCreateInstance()函数创建IUIAutomation接口的实例,然后使用IUIAutomation::ElementFromHandle()方法从按钮的HWND获取IUIAutomationElement接口(或获取按钮的IUIAutomationElement界面通过其他方式),然后使用IUIAutomation::AddAutomationEventHandler()方法订阅该按钮的UIA_Invoke_InvokedEventId事件。

  5. 如果您拥有目标按钮的HWND,则可以使用GetWindowThreadProcessId()来检索按钮的进程ID和线程ID。您将需要按钮的父窗口HWND(如果需要,您可以使用GetParent()获取)以使用SetWindowsLongPtr(GWL_WNDPROC)SetWindowSubclass()

    SetWindowsHookEx()SetWinEventHook()允许您指定要挂钩的特定线程ID(在SetWinEventHook()的情况下也指定特定的进程ID),这样您就可以最大限度地减少开销中使用的开销挂钩。 CreateRemoteThread()需要目标流程句柄,您可以使用流程ID通过OpenProcess()获取该句柄。

    所以,正如你所看到的,你所要求的并不是微不足道的。在我看来(不是确定的),在编码方面,从最简单到最难的技术顺序是:

    1. SetWinEventHook()没有DLL(但会以影响性能为代价)。

    2. UI Automation

    3. SetWindowsHookEx()或带有DLL的SetWinEventHook()

    4. SetWindowsHookEx()因为额外的注入代码和子类化