[Solved] Correctly receive messages from button


To detect a button press in another process, you have to hook that process. You have four choices for doing that:

  1. use SetWindowsHookEx() to install a WH_CALLWNDPROC or WH_GETMESSAGE hook into the target process to catch the WM_COMMAND/BN_CLICKED message that is sent to the button’s parent window when the button is clicked. The message identifies the HWND and ID of the button that was clicked. The hook must be implemented in a DLL so it can be injected into another process.

  2. use SetWinEventHook() to catch the EVENT_OBJECT_INVOKED event when the button is clicked. The hook callback identifies the HWND and ID of the button that was clicked. The hook should be implemented in a DLL so it can be injected into the target process for better performance, but is not required. If you do not use a DLL, the hooking thread must have a message loop to receive the events as they will have to be passed across process boundaries.

  3. use SetWindowsHookEx() or CreateRemoteThread() to inject code into the target process and have that code then subclass the button’s parent window using SetWindowsLongPtr(GWL_WNDPROC) or SetWindowSubclass() in order to catch the WM_COMMAND/BN_CLICKED message that is sent to that parent window.

  4. use UI Automation. Create an instance of the IUIAutomation interface using the CoCreateInstance() function, then use the IUIAutomation::ElementFromHandle() method to get an IUIAutomationElement interface from the button’s HWND (or obtain the button’s IUIAutomationElement interface through other means), then use the IUIAutomation::AddAutomationEventHandler() method to subscribe to the UIA_Invoke_InvokedEventId event for that button.

If you have the HWND of the target button, you can use GetWindowThreadProcessId() to retrieve the button’s process ID and thread ID. You will need the button’s parent window HWND (which you can get using GetParent() if needed) in order to use SetWindowsLongPtr(GWL_WNDPROC) or SetWindowSubclass().

SetWindowsHookEx() and SetWinEventHook() allow you to specify the specific thread ID to hook (and in the case of SetWinEventHook(), the specific process ID as well) so you can minimize overhead used in hooking. CreateRemoteThread() requires the target process handle, which you can get with OpenProcess() using the process ID.

So, as you can see, what you are asking for is not going to be trivial to implement. In my opinion (not definitive), the order of techniques from easiest to hardest, in terms of coding, would be:

  1. SetWinEventHook() without a DLL (but at the cost of affecting performance).

  2. UI Automation.

  3. SetWindowsHookEx(), or SetWinEventHook() with a DLL.

  4. SetWindowsHookEx() because of the extra injection code and subclassing

5

solved Correctly receive messages from button