0

I got a WM_COMMAND in a button event by Spy++, It looks like:

image

<000116> 001B0A02 S WM_NOTIFY idCtrl:133978 pnmh:0019F9A0
<000117> 001B0A02 R WM_NOTIFY
<000118> 001B0A02 S WM_COMMAND wNotifyCode:0000 wID:2 hwndCtl:00020B5A
<000119> 001B0A02 R WM_COMMAND
<000120> 001B0A02 S WM_NOTIFY idCtrl:133978 pnmh:0019F9BC
<000121> 001B0A02 R WM_NOTIFY

Then I tried to redo WM_COMMAND by SendMessage:

image

Nothing happened. I used the AHK script to be sure, same result.

When I used SendMessage(), Spy++ got this:

<000423> 001B0A02 S WM_COMMAND wNotifyCode:0000 wID:2 hwndCtl:00000014
<000424> 001B0A02 R WM_COMMAND

I also let the lParam = 0, then it worked but not as I expected, another Menu item opened.

<000001> 001B0A02 S WM_COMMAND wNotifyCode:0 (sent from a menu) wID:2

So how can I do this?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Lain
  • 13
  • 2
  • This is not how you automate a UI. UI Automation is done using [UI Automation](https://learn.microsoft.com/en-us/windows/win32/winauto/entry-uiauto-win32). – IInspectable Aug 12 '21 at 17:56

1 Answers1

1

To emulate the WM_COMMAND for a button click, you need to send the ID of your button and the BN_CLICKED notification code (combined) as the wParam argument to SendMessage(), and the handle (HWND) of the button as the lParam.

If hDlg is the handle of your dialog window, and IDC_MYBUTTON is the resource ID of your button, the call would be like this:

SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_MYBUTTON, BN_CLICKED), (LPARAM)GetDlgItem(hDlg, IDC_MYBUTTON));

As it happens, the BN_CLICKED notification code has a value of 0, so the wParam value will be just the control ID; this appears to be 2 in your case – the value used by Windows for the "Cancel" button. The problem, in your code, seems to be an invalid window handle for the lParam argument.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • @Lain I notice that your first image suggests that your button is part of a control bar or dialog bar. If you can clarify exactly what that is, and how you have created it, then I can (maybe) edit my answer to be more specific to your use case. – Adrian Mole Aug 11 '21 at 09:04
  • An easier way to handle this is to send [`BM_CLICK`](https://learn.microsoft.com/en-us/windows/win32/controls/bm-click) to the button itself, and let it handle sending `WM_COMMAND/BN_CLICKED` to its parent. – Remy Lebeau Aug 11 '21 at 18:16
  • @Remy Indeed! But the (possible) problem still remains if it's a control bar, about how to get the relevant `HWND` for the "button itself". For a dog-box, it's easy; for any of the new-style "magic" bars, it's not so trivial. – Adrian Mole Aug 11 '21 at 21:52
  • @Adrian Mole Thank you for your answer, I'm a novice so I wasted some time figuring it out. As you said, I need an `HWND`, which is the handle of the button. I tried to SPY++ it, but there's no such thing, the handle that SPY++ gave me (`00020B5A`)is the handle of the Toolbar. Then I tried to figure out what the button exactly is, I found this in SPY++ ```WM_DRAWITEM ID: 464210 Control type: ODT_BUTTON Item ID: 0 Item action: ODA_FOCUS Item state: ODS_FOCUS | ODS_NOFOCUSRECT Hwnd item: 0x00071552 Item RECT: 0, 0, 220, 52 Item data: 0x00000000 HDC: 0xbe015650 ``` – Lain Aug 12 '21 at 09:47
  • Does this mean that this button is not a normal button but an Owner-drawn button? I've googled it all day but got nothing useful. My purpose is to use something like AHK to redo the operation of clicking the button in the background. Could you give me some hints? Thank you for your help. – Lain Aug 12 '21 at 09:47
  • Then I found this: Then I found this: ```WM_NOTIFY Control ID: 398700 From Hwnd: 0x0006156c From ID: 0x0006156c Code: NM_CLICK ``` – Lain Aug 12 '21 at 11:30