xSiGiNx
asked on
Winapi: Click/Press emulation button in another application.
I have handle to button in some application, that does not belong to my thread space.
I use this code:
Windows.SendMessage(HANDLE ,WM_LBUTTO NDOWN,0,0) ;
Windows.SendMessage(HANDLE ,WM_LBUTTO NUP,0,0);
to emulate click/keypress on this button.
However, I doubt, that it is most nice and elegant solution - is there any better?
PS: Method shouldn't involve AttachThreadInput calls, and should work on 98 and XP as well.
I use this code:
Windows.SendMessage(HANDLE
Windows.SendMessage(HANDLE
to emulate click/keypress on this button.
However, I doubt, that it is most nice and elegant solution - is there any better?
PS: Method shouldn't involve AttachThreadInput calls, and should work on 98 and XP as well.
>>is there any better?
Usually, you'd use 'SendInput()' to do that - see http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/sendinput.asp ("SendInput Function")
Usually, you'd use 'SendInput()' to do that - see http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/sendinput.asp ("SendInput Function")
ASKER
It seems close, but.. How do I use this function to send "event", if I have handle (HWND) of control?
ASKER
Naw.. Not close. It seems, like it is something almost like keybd_event, which doesn't care to which control I am sending message.
And I need to send message to control directly.
And I need to send message to control directly.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Looks rather nice.. here it is translated to delphi:
procedure MyClick(Wnd,Child:HWND);
begin
Windows.SendMessage(Wnd,WM _COMMAND,G etDlgCtrlI D(Child),C hild);
end;
Where Wnd is Parent (Form where component is placed) and Child is Button..
It looks like it is what it should be.. But for same silly reason it doesnot just work.. =(
Perhaps its only work if AttachThreadInput is called beforehand?
Too late for me today, will test tomorrow.
procedure MyClick(Wnd,Child:HWND);
begin
Windows.SendMessage(Wnd,WM
end;
Where Wnd is Parent (Form where component is placed) and Child is Button..
It looks like it is what it should be.. But for same silly reason it doesnot just work.. =(
Perhaps its only work if AttachThreadInput is called beforehand?
Too late for me today, will test tomorrow.
Replace SendMessage with PostMessage. AttachThreadInput doesn't matter, Windows messages are always handled in the destination window thread.
Program may ignore WM_COMMAND message only if it is written by some special way - for example, handles button clicks instead of handling WM_COMMAND message. However, this way works for 99% of programs.
Using Spy++ see what message is sent to the button parent when button is clicked. Try to click button programmatically using this utility:
http://www.codeproject.com/tools/MessageSender.asp
If you can do this using message handler, it is possible to do the same in the program. Posting the WM_COMMAND message is the simplest way, in the rare case it is not working by some reason, use SendInput as jkr writes. Having button HWND you can get it's rectangle (see GetWindowRect), move mouse cursor to some point inside of this rectangle (SetCursorPos) and make click using SendInput.
Program may ignore WM_COMMAND message only if it is written by some special way - for example, handles button clicks instead of handling WM_COMMAND message. However, this way works for 99% of programs.
Using Spy++ see what message is sent to the button parent when button is clicked. Try to click button programmatically using this utility:
http://www.codeproject.com/tools/MessageSender.asp
If you can do this using message handler, it is possible to do the same in the program. Posting the WM_COMMAND message is the simplest way, in the rare case it is not working by some reason, use SendInput as jkr writes. Having button HWND you can get it's rectangle (see GetWindowRect), move mouse cursor to some point inside of this rectangle (SetCursorPos) and make click using SendInput.
When you PostMessage to the parent, you are missing a parameter, the high word of wParam. Do this:
int nID = GetDlgCtrlID(hButton);
HWND hParent = GetParent(hButton);
if ( hParent )
PostMessage(hParent, WM_COMMAND,
(WPARAM)MAKELONG(nID, NM_CLICK),
(LPARAM)hButton);
int nID = GetDlgCtrlID(hButton);
HWND hParent = GetParent(hButton);
if ( hParent )
PostMessage(hParent, WM_COMMAND,
(WPARAM)MAKELONG(nID, NM_CLICK),
(LPARAM)hButton);
Ok, to translate that wParam to delphi (I guess...don't know that language, you'll get it :):
wParam = (NM_CLICK << 16) | nId;
Where NM_CLICK is actually 0xfffe
If defines are a problem, just:
wParam = 0xfffe0000 | (nId & 0xffff);
Where | and & are bitwise.
wParam = (NM_CLICK << 16) | nId;
Where NM_CLICK is actually 0xfffe
If defines are a problem, just:
wParam = 0xfffe0000 | (nId & 0xffff);
Where | and & are bitwise.
ASKER
Still didn't work.. However, I've pinpointed problem to this point:
CtrlID:=Windows.GetDlgCtrl ID(Child);
CtrlID.. Is same as Child. Same number. How could that be? Bug in delphi libs or I just miss something about this function?
MSDN gives me this:
"If the function succeeds, the return value is the identifier of the control.
If the function fails, the return value is zero."
CtrlID:=Windows.GetDlgCtrl
CtrlID.. Is same as Child. Same number. How could that be? Bug in delphi libs or I just miss something about this function?
MSDN gives me this:
"If the function succeeds, the return value is the identifier of the control.
If the function fails, the return value is zero."
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Oops, typos. rect should be rectCtl
ASKER
Thx for all replies. I am still inclined to AlexFM solution.. And it even works (Spy++ does give Control's ID - how the heck it GETS it?)
I am really curios, if it's delphi problem, so i try to rewrite call to API in inline ASM.. However - silly question:
How does calling API works in asm?
I mean if this right:
mov eax,HWND
call GetDlgCtrlId
mov CtrlID,eax
Or this:
push eax
call GetDlgCtrlId
pop eax
After I get answer, I'll finish question rewardin participants (probably raisin value)
I am really curios, if it's delphi problem, so i try to rewrite call to API in inline ASM.. However - silly question:
How does calling API works in asm?
I mean if this right:
mov eax,HWND
call GetDlgCtrlId
mov CtrlID,eax
Or this:
push eax
call GetDlgCtrlId
pop eax
After I get answer, I'll finish question rewardin participants (probably raisin value)
ASKER
I got it working. Thx a lot =) I omitted dialog control id at all (used 0).
ASKER