To detect a button press in another process, you have to hook that process. You have four choices for doing that:
-
use
SetWindowsHookEx()
to install aWH_CALLWNDPROC
orWH_GETMESSAGE
hook into the target process to catch theWM_COMMAND/BN_CLICKED
message that is sent to the button’s parent window when the button is clicked. The message identifies theHWND
and ID of the button that was clicked. The hook must be implemented in a DLL so it can be injected into another process. -
use
SetWinEventHook()
to catch theEVENT_OBJECT_INVOKED
event when the button is clicked. The hook callback identifies theHWND
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. -
use
SetWindowsHookEx()
orCreateRemoteThread()
to inject code into the target process and have that code then subclass the button’s parent window usingSetWindowsLongPtr(GWL_WNDPROC)
orSetWindowSubclass()
in order to catch theWM_COMMAND/BN_CLICKED
message that is sent to that parent window. -
use UI Automation. Create an instance of the
IUIAutomation
interface using theCoCreateInstance()
function, then use theIUIAutomation::ElementFromHandle()
method to get anIUIAutomationElement
interface from the button’sHWND
(or obtain the button’sIUIAutomationElement
interface through other means), then use theIUIAutomation::AddAutomationEventHandler()
method to subscribe to theUIA_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:
-
SetWinEventHook()
without a DLL (but at the cost of affecting performance). -
SetWindowsHookEx()
, orSetWinEventHook()
with a DLL. -
SetWindowsHookEx()
because of the extra injection code and subclassing
5
solved Correctly receive messages from button