3

I am trying to generate an click event in a third party application. As a start I tried to simulate a click in calculator. Here's the code"

IntPtr hwnd = IntPtr.Zero;
IntPtr hwndChild = IntPtr.Zero;
//Get a handle for the Calculator Application main window
hwnd = FindWindow(null, "Calculator");

hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "1");

//send BN_CLICKED message
SendMessage(hwndChild, BM_CLICK, IntPtr.Zero, IntPtr.Zero);

But using this code I am not getting the handle of the button. Could someone help please. Is there any other way to simulate a button click on third party application?

Thanks.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Nikil
  • 369
  • 2
  • 5
  • 17
  • 1
    Shouldn't BM_CLICK be WM_CLICK? – Flipster Jan 17 '11 at 16:24
  • I think flip is correct as you need to send it as a window message, if you want to do it easily you can use Spy++ to find the names and even specific handles to then put into your code. – Jesus Ramos Jan 17 '11 at 16:27
  • @FlipScript: I think they both work, don't they? – user541686 Jan 17 '11 at 16:28
  • @FlipScript, @Jesus: Actually, `BM_CLICK` is correct for buttons. There is no generic `WM_CLICK` message in the Win32 API since not all controls support the notion of "clicking". – casablanca Jan 17 '11 at 16:31
  • Are you sure that your Calculator app uses individual windows for its buttons. Sometimes they just draw the buttons direct to the canvas and then use hit testing. Have you checked with Spy? – David Heffernan Jan 17 '11 at 16:33
  • @Ramos: If I fetch handle using spy++ how can I pass the same using sendMessage? – Nikil Jan 17 '11 at 16:37
  • It started to work when I replaced public const uint BM_CLICK = 0x00F5; with public const uint WM_LBUTTONDOWN = 0x0201; public const uint WM_LBUTTONUP = 0x0202; and used SendMessage(buttonHandle, WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero); SendMessage(buttonHandle, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero); .Thanks – Nikil Jan 17 '11 at 18:18

4 Answers4

1

Your general approach is correct, but there are two potential problems with your code:

  1. FindWindowEx only finds direct children of the specified window. It's possible that the calculator buttons are laid out in a container window which is a child of the main window, so the button wouldn't be a direct child of the main window.

  2. The documentation for BM_CLICK says that it simulates a click by sending mouse down and up messages and hence you may have to activate the parent window before sending this message.

casablanca
  • 69,683
  • 7
  • 133
  • 150
  • Is this usage correct. I am declaring this in the begining public const uint BM_CLICK = 0x00F5; – Nikil Jan 17 '11 at 17:44
1

It started to work when I replaced

public const uint BM_CLICK = 0x00F5;

with

public const uint WM_LBUTTONDOWN = 0x0201; 
public const uint WM_LBUTTONUP = 0x0202;

and used

SendMessage(buttonHandle, WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero); 
SendMessage(buttonHandle, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
Nikil
  • 369
  • 2
  • 5
  • 17
0

First use SPY++ to find that is a button having Handle.

In some cases the controls that looks like Button can be graphic control. The difference is the graphic control will not have Handle, but the Windows control will have handle. If that control has valid Handle.Then use FindWindowEx

Also give Parent window Handle (I think first parameter, May be you have to use GetWindow() using the caption)

Then send click message.

KBBWrite
  • 4,373
  • 2
  • 20
  • 22
0

If you haven't the handle of the button, you can emulate mouse clicking on coordinates:

class User32
 { 
    [Flags]
    public enum MouseEventFlags
    {
        LEFTDOWN = 0x00000002,
        LEFTUP = 0x00000004,
        MIDDLEDOWN = 0x00000020,
        MIDDLEUP = 0x00000040,
        MOVE = 0x00000001,
        ABSOLUTE = 0x00008000,
        RIGHTDOWN = 0x00000008,
        RIGHTUP = 0x00000010
    }

    [DllImport("user32.dll")]
    public static extern bool SetCursorPos(int X, int Y);

    [DllImport("user32.dll")]
    public static extern void mouse_event(uint dwFlags, 
                                   uint dx, 
                                   uint dy, 
                                   uint dwData,
                                   int dwExtraInfo);

    [DllImport("user32.dll")]
    public static extern void mouse_event(uint dwFlags, 
                                   uint dx, 
                                   uint dy, 
                                   uint dwData,
                                   UIntPtr dwExtraInfo);
}

class Program
{
     static void Main()
     {
         User32.SetCursorPos(25, 153);
         User32.mouse_event((uint)User32.MouseEventFlags.LEFTDOWN, 25, 153, 0, 0);
         User32.mouse_event((uint)User32.MouseEventFlags.LEFTUP, 25, 153, 0, 0);
     }
}

But, function SetCursorPos set cursor position in global coordinates of screen, so fist you shoud get the possition of a third party application's window.

IamMan
  • 322
  • 1
  • 2
  • 13