Is there any way to programmatically close an opened pop-up menu that was invoked with an API like TrackPopupMenu?
Posted on 2002-12-22 00:09:57 by comrade
how about focusing(SetFocus) on a different window?

Just an idea, dunno if it works... :grin:
Posted on 2002-12-22 00:14:29 by stryker
Simulate a 'ESC' press would do. But it should be made sure there's no conflict.:)
Posted on 2002-12-22 00:28:57 by C.Z.
How does Windows do it when you move across menus?
Posted on 2002-12-22 09:44:38 by comrade
If you mean as you scroll across the top of the menu after you've selected a dropdown menuitem, it seems to use a series of WM commands - _MOUSEMOVE/_MOUSEFIRST, _UNINITMENUPOPUP, _MENUSELECT, _INITMENUPOPUP, _INITMENU.

Normally TrackPopupMenu waits for you to select a menu item then sends the WM_COMMAND message to the owner window you specified, so you could also send this message programatically to a hidden dummy menu item on the popupmenu and just return without handling it. This should fake the popupmenu into closing, though any refocussing of the mouse should do the same.
Posted on 2002-12-22 11:09:13 by Kayaker
Sorry im no help, but i am equally as interested in finding the solution. I've found myself frustrated looking for the same once before ;)

There has to be a clean solution, with out 'faking'....

Posted on 2002-12-23 18:39:01 by NaN
People forums told me WM_CANCELMODE.
Posted on 2002-12-23 23:17:17 by comrade
I'm curious, are you guys trying to close a TrackPopupMenu menu or a standard dropdown menu? My first thought was *why* you would want to do this programatically, but looking at a popup menu closer I could see you might want to do this if the mouse is moved off the menu and you don't want to bother the user with having to click elsewhere or hit ESC to inactivate the menu if they don't select anything.

While WM_CANCELMODE or some other method might work, the problem seems to be how to trap an event such that you can actually send the message. I did a bit of testing with a listview popup menu. Once a TrackPopupMenu menu is shown no other messages are sent to the parent window or elsewhere until you click something, in which case there's no need to close it programatically of course. Even simple WM_MOUSEMOVE or WM_PAINT messages don't register if the menu is still on screen. TrackPopupMenu actually thunks down to the 16-bit GetMenuString API in User.exe and after displaying the strings enters a WAITMESSAGE / DISPATCHINPUT loop, checking for certain messages including WM_LBUTTONDOWN, WM_MBUTTONDOWN and WM_RBUTTONDOWN, among a few others.

If you're dealing with a regular dropdown menu you might be able to intercept WM_MOUSEMOVE, since it seemed to register in a message spy, but TrackPopupMenu seems locked in a loop that I don't know how you could get into without a hook of some kind (the 16-bit CallNextHookEx is actually called as part of the 16-bit GetMenuString WAITMESSAGE loop as well).

I tried using SetCapture to direct mouse input to a window of my choice before calling TrackPopupMenu, but it wasn't valid while the popup menu was active. Just curious what you're trying to do...;)

Posted on 2002-12-24 00:25:28 by Kayaker

For your ease of mind, i was trying to have pop-up menus appear on voice command with my SR stuff (in the COM section). If the person says 'Cancle / Esc' or it times out, i wanted the menu close. But i didnt have much reliable luck with it.

Posted on 2002-12-24 00:35:52 by NaN
EndMenu - 98 and 2k :)

usually when you press ESC on a right click menu, Windo$e will sent you back to the last window(edit control, listbox...) in focus. So why not use GetFocus before TrackPopupMenu then use SetFocus to cancel the menu. :)

anyway just use WM_CANCELMODE, it's much better and easier. :)
Posted on 2002-12-24 00:43:32 by stryker
"Just curious what you're trying to do..."

CreatePMHook: ;
call GetCurrentThreadId ;
push eax ; eax->hThreadID
push 0 ; handle to application instance
push offset pMessageProcPM ; our hook proc
push WH_MSGFILTER ; hook type
call SetWindowsHookEx ; call API
mov hHookID1, eax ; handle to hook procedure
ret ;
KillPMHook: ;
push hHookID1 ; handle to hook procedure
call UnhookWindowsHookEx ; call API
mov hHookID1, 0 ; clear variable
ret ;
;[esp] -> return address
;[esp+4] -> nCode = hook code
;[esp+8] -> wParam = current-process flag
;[esp+12] -> lParam = message data -> lp to CWPSTRUCT
pMessageProcPM: ;
pop ecx ; ecx->return address
push hHookID1 ; hHookID1->param of CallNextHookEx
mov edx, [esp+4] ; nCode
mov eax, [esp+12] ; lParam-> lp MSG
push ecx ; ecx->return address
cmp edx, MSGF_MENU ; edx->nCode = MSGF_MENU
mov ecx, hMenuT1 ;
jnz CallNextHookEx ; call API
cmp [eax].MSG.hwnd, ecx ;
jnz CallNextHookEx ; call API[B]
cmp [eax].MSG.message, WM_NOTIFY ; trap WM_NOTIFY [/B]
jnz CallNextHookEx ; call API
mov edx, [eax].MSG.lParam ;
mov ecx, [eax].MSG.wParam ;
push edx ; lParam
push ecx ; wParam [B]
push WM_NOTIFY ; trap WM_NOTIFY [/B]
push hWnd ; main window handle
push offset CallNextHookEx ; return address of SendMessage->call API
jmp SendMessage ;

Posted on 2002-12-24 08:45:35 by lingo12
Thanks Lingo, I'll play with the idea ;)

Posted on 2002-12-25 23:07:11 by Kayaker