How to get HWND and click for Menu/SubMenu/SubMenuItem? - winapi

I'm working on an App and it has SubMenu/One more child SubMenu like Edit --> Insert --> Date and few other option. I want to click(sendmessage) to Date menuitem. is there any PinvokeMethod to get handle for multilevel menu Items?

To simulate the click of a menu you do not send any message to the menu itself, you just send the same message that the menu does when clicked. That is, send WM_COMMAND to the owner window of the menu, with old good SendMessage.
When choosing an option from a menu, the parameters are:
wParam: the identifier (16 lower bits) of the command to be sent.
lParam: 0.
If you don't know the value of the identifier, you can use a monitor program such as Spy++ (included with most VS versions) to list the messages sent/received by your program.

Related

Is it possible to see where control focus is being lost to?

I have a ClistCtrl (wraps Windows list view for non-MFC users) on a dialog. I set functionality that when the list loses focus, any selected items are unselected.
I also have a "remove items" button, whose on-click handler will delete any selected items in the list.
The idea is you select items in the list, and then either click the button to remove these items, or click somewhere else and the selection is cancelled.
But, when you click the delete button, the list loses focus first and therefore nothing happens! Is there a way around this?
You can receive message about lost focus with WM_KILLFOCUS, its wParam will give you a handle to window which got focus:
wParam
A handle to the window that receives the keyboard focus. This
parameter can be NULL.
You should be able to use Spy++ to see WM_KILLFOCUS on you list window, and read its wParam - and later find also with spy++ which window is it.
As said in other posts, you can use WM_KILLFOCUS for that.
But I think it's a very bad idea to clear the selection on losing focus.
Just imagine: the user selects a whole bunch of items using multiselect (using shift, ctrl, scrollbar..), and then, one of the following happens:
The phone rings, urgent call - the user needs to check a mail: selection: gone!
An annoying message box pops up taking focus (yes, it does happen): selection -> gone.
Your users might hate you for this, so don't do it :) (not even if there are only 3 items in the listcontrol).
The usual way is to gray the selection on losing focus. You could add a 'clear selection' button, but even that isn't needed. Just clicking on one item will clear the selection (except for that one item of course).
Bottom line: don't clear the selection on losing focus, ever.
Update:
If the selection is not visible on losing focus, the LVS_SHOWSELALWAYS flag is what you need:
LVS_SHOWSELALWAYS
The selection, if any, is always shown, even if the control does not
have the focus.

Win32, How to access button on toolbar

Let's say I have a compiled binary program that runs and exposes some GUI on the screen.
I need from another program in Win32 to access its toolbar, find a button and click on it.
I know how to find Hwnd of the toolbar, but I don't really know how to enumerate the buttons on it.
Any ideas how to do it in Win32 calls?
Is there any tool like Spy++ that is capable of showing button handles under toolbar?
Spy++ doesn't do it.
Thanks
If it is a standard Win32 Toolbar control, then you send the toolbar a TB_BUTTONCOUNT message to determine how many buttons are on the toolbar, then send a TB_GETBUTTON message to retrieve information about a button at a given index.
The tricky part is that the TBBUTTON structure that receives the button info needs to be allocated in the same process that owns the toolbar, so you will have to:
call GetWindowThreadProcessId() to retrieve the toolbar's process ID
call OpenProcess() to get a HANDLE to that process
call VirtualAllocEx() to allocate the structure inside of that process
send the TB_GETBUTTON message(s) to the toolbar, specifying the pointer returned by VirtualAllocEx()
call ReadProcessMemory() to copy the structure data back into your own process so you can process it as needed
call VirtualFreeEx() to free the allocated memory.
When the button is clicked it sends a WM_COMMAND message to the main window. Simulating a click on a toolbar button is not very practical. A better approach is to use Spy++ to find the WM_COMMAND message and its parameters. Then in your program send this same WM_COMMAND message.
AFAIR you can get the HWND of a toolbar button by calling GetDlgItem. The first parameter is the HWND of the toolbar, the second parameter is the ID of the button (the one you set in its TBBUTTON structure). You need to have the button ID to use this approach.
=== EDIT ===
In addition to EnumChildWindows, suggested by #graham.reeds, you can try SendInput. Move the target window to the foreground, calculate the screen coordinates of the upper-left corner of the toolbar (using its HWND), add the X-Y offset of the middle of the target button, and send a mouse click to that position. (I used this approach successfully to click on Flash and Silverlight objects rendered inside the IE window.)
Off the top of my head:
Use EnumChildWindows to find the child controls of the toolbar.
Then use GetWindowText to see if it is a button.
If it is PostMessage to it to invoke it's operation.

return key generates IDOK for button with focus

I did a SetFocus to a button in a dialog. The button gets the dashed outline. When the user presses the return key, the dialog get a IDOK message rather than a message from the button were I set the focus. The same thing happens under other circumstances.
Why is this happening? And how can I cause the return to act as a button press?
Plain c++ windows app, no MFC, no NET.
Feature, not a bug. The [Enter] key operates the button that's marked as the default button for a dialog. Either with the DEFPUSHBUTTON in the .rc file or the BS_DEFPUSHBUTTON style flag. Which is typically the "OK" button so getting IDOK back is expected. The [Escape] key is special that way too, typically the [Cancel] button. This is bound to ring a bell if you think back on how you used dialogs before.
You click a button that has the focus by pressing the space bar instead.
In another SO question I found KB article that might help you:
If a dialog box or one of its controls currently has the input focus,
then pressing the ENTER key causes Windows to send a WM_COMMAND
message with the idItem (wParam) parameter set to the ID of the
default command button. If the dialog box does not have a default
command button, then the idItem parameter is set to IDOK by default.
When an application receives the WM_COMMAND message with idItem set to
the ID of the default command button, the focus remains with the
control that had the focus before the ENTER key was pressed. Calling
GetFocus() at this point returns the handle of the control that had
the focus before the ENTER key was pressed. The application can check
this control handle and determine whether it belongs to any of the
edit controls in the dialog box. If it does, then the user was
entering data into one of the edit controls and after doing so,
pressed ENTER. At this point, the application can send the
WM_NEXTDLGCTL message to the dialog box to move the focus to the next
control.
According to MSDN,
Dialog Box Keyboard Interface
The system provides a special keyboard interface for dialog boxes that carries out special processing for several keys. The interface generates messages that correspond to certain buttons in the dialog box or changes the input focus from one control to another. Following are the keys used in this interface and their respective actions.
...
ENTER: Sends a WM_COMMAND message to the dialog box procedure. The wParam parameter is set to IDOK or control identifier of the default push button.
Since the system intercepts and processes ENTER key pressed directly through the dialog, you'll need to handle it in your dialog box procedure by calling GetFocus() to first see which control has the focus, and perform the appropriate action for that particular control.

checkbox - change notification

What notification code is sent with the wm_command message to the dialog box procedure when a check box changes state?
And more importantly, where would I look in the msdn to find the notification codes for various controls?
Note that Check boxes and Radio buttons are Buttons. So they send click and double click messages, BN_CLICKED and BN_DOUBLECLICKED.
If you use MFC, then you can examine the check state with CButton::GetCheck method.
Otherwise you send the BM_GETCHECK message to the control: SendMessage(button_handle, BM_GETCHECK, 0, 0);
SendMessage can return
BST_CHECKED Button is checked.
BST_INDETERMINATE Button is grayed, indicating an indeterminate state
(applies only if the button has the BS_3STATE or BS_AUTO3STATE style).
BST_UNCHECKED Button is cleared
If the button has a style other than those listed, the return value is zero.
If you use the Visual Studio, the easiest way to get a list of events/messages a control can send is to go to Resource/Design view, right click a control and select Events.
For a list of common controls see: Control Library
(in the page you'll see a popup menu with the controls if you hover the cursor on the Control Library link)
It's BN_CLICKED. The bottom of the page links to the button messages.

Setting the width of a menu in the Windows API

I'm creating a custom control in wxWidgets that displays a menu as part of it, and currently working on the Windows side of things. wxWidgets doesn't have a way of setting the width of a menu. It just makes the window as wide as the longest string plus a few pixels on either side.
In the API, there is a way to get the actual Windows API menu handle. Does the Windows API have a method of setting the width of a menu other than just calculating it on its own based on the width of the string?
With the handle of the menu, you can cycle through the menu items and call SetMenuItemInfo, indicating that you want to owner-draw the menu items. When you do this, the window that the menu is attached to will receive the WM_MEASUREITEM message, which you would then respond to by setting the dimensions required for the menu. It is here you can set your width.
Of course, this means you have to subclass the windows message handler for the window that contains the menu.
First of all, try to obtain the HWND to the menu:
(1) WM_DRAWITEM (2)get the HDC (3)WindowFromDC(),
then you can arbitrarily adjust aspects of the menu.
NOTE: don't send WM_QUIT WM_CLOSE to the menu, or you'll effectively shut down your computer with no clue.

Resources