Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Winapi: Click/Press emulation button in another application.

Posted on 2004-08-13
14
6,637 Views
Last Modified: 2013-12-03
I have handle to button in some application, that does not belong to my thread space.

I use this code:

 Windows.SendMessage(HANDLE,WM_LBUTTONDOWN,0,0);
 Windows.SendMessage(HANDLE,WM_LBUTTONUP,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.

0
Comment
Question by:xSiGiNx
  • 7
  • 4
  • 2
  • +1
14 Comments
 

Author Comment

by:xSiGiNx
ID: 11794570
Btw code was using Delphi. Actually no difference. What I need is some sane windows message, that I could send to control (button)
0
 
LVL 86

Expert Comment

by:jkr
ID: 11794841
0
 

Author Comment

by:xSiGiNx
ID: 11795146
It seems close, but.. How do I use this function to send "event", if I have handle (HWND) of control?
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 

Author Comment

by:xSiGiNx
ID: 11795228
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.
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 60 total points
ID: 11795532
Having any button handle you can programmatically click this button by the following way:

int nID = GetDlgCtrlID(hButton);
HWND hParent = GetParent(hButton);

if ( hParent )
    PostMessage(hParent, WM_COMMAND,  nID, hButton);
0
 

Author Comment

by:xSiGiNx
ID: 11797099
Looks rather nice.. here it is translated to delphi:

procedure MyClick(Wnd,Child:HWND);
begin
Windows.SendMessage(Wnd,WM_COMMAND,GetDlgCtrlID(Child),Child);
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.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 11798633
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.
0
 
LVL 8

Expert Comment

by:adg080898
ID: 11798722
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);
0
 
LVL 8

Expert Comment

by:adg080898
ID: 11798738
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.
0
 

Author Comment

by:xSiGiNx
ID: 11798741
Still didn't work.. However, I've pinpointed problem to this point:

CtrlID:=Windows.GetDlgCtrlID(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."

0
 
LVL 8

Assisted Solution

by:adg080898
adg080898 earned 20 total points
ID: 11798785
Is it a control in a dialog box? If it is not a control in a dialog box then the concept of "control id" is optional and may not necessarily be used.

You could try injecting a WM_LBUTTONDOWN/WM_LBUTTONUP pair to see if it handles the click at that level. Forget the parent, let the control route it to its parent if that's what it does. Probably more reliable that way:

// Get center of button
RECT rectCtl;
GetClientRect(hChild, &rectCtl);
rect.left = rect.right / 2;
rect.top = rect.bottom / 2;

if (hChild) {
    PostMessage(hChild, WM_LBUTTONDOWN,
            MK_LBUTTON,
            (rect.left & 0xffff) | (rect.top << 16));
    PostMessage(hChild, WM_LBUTTONUP,
            0,
            (rect.left & 0xffff) | (rect.top << 16));
}
0
 
LVL 8

Expert Comment

by:adg080898
ID: 11798788
Oops, typos. rect should be rectCtl
0
 

Author Comment

by:xSiGiNx
ID: 11800532
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)
0
 

Author Comment

by:xSiGiNx
ID: 11800740
I got it working. Thx a lot =) I omitted dialog control id at all (used 0).  
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
catastrophic failure exception from hresult 0x8000ffff e_unexpected 9 121
Problem to DocumentFormat 8 110
Dialogbox API leak? 18 98
windbg taking it's time 32 93
What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

860 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question