Holy cow, I wrote a book!
Last week we looked at menu drag/drop. Another little-used menu feature added in Windows 2000 is the ability to show context menus on menus. The message is WM_MENURBUTTONUP and the flag is TPM_RECURSE. Let's demonstrate with a simple program.
WM_MENURBUTTONUP
TPM_RECURSE
Start with the scratch program, and add the MoveMenuItem function just so our context menu can do something.
MoveMenuItem
// resource header file #define IDM_MAIN 1 #define IDM_POPUP 2 #define IDC_MOVEUP 200 #define IDC_MOVEDOWN 201 // resource file 1 MENU PRELOAD BEGIN POPUP "&Test" BEGIN MENUITEM "&Red", 100 MENUITEM "&Orange", 101 MENUITEM "&Yellow", 102 MENUITEM "&Green", 103 MENUITEM "&Blue", 104 MENUITEM "&Violet", 105 END END 2 MENU PRELOAD BEGIN POPUP "" BEGIN MENUITEM "Move &Up", IDC_MOVEUP MENUITEM "Move &Down", IDC_MOVEDOWN MENUITEM SEPARATOR MENUITEM "&Cancel", IDCANCEL END END // scratch.cpp #define HANDLE_WM_MENURBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (HMENU)(lParam)), 0L) void OnMenuRButtonUp(HWND hwnd, UINT uPos, HMENU hmenu) { if (hmenu == GetSubMenu(GetMenu(hwnd), 0)) { HMENU hmenuPopup = LoadMenu(g_hinst, MAKEINTRESOURCE(IDM_POPUP)); if (hmenuPopup) { if (uPos == 0) { EnableMenuItem(hmenuPopup, IDC_MOVEUP, MF_DISABLED | MF_GRAYED); } if (uPos == GetMenuItemCount(hmenu) - 1) { EnableMenuItem(hmenuPopup, IDC_MOVEDOWN, MF_DISABLED | MF_GRAYED); } DWORD dwPos = GetMessagePos(); UINT idCmd = TrackPopupMenuEx(GetSubMenu(hmenuPopup, 0), TPM_RECURSE | TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), hwnd, NULL); switch (idCmd) { case IDC_MOVEUP: MoveMenuItem(hmenu, uPos, uPos - 1); break; case IDC_MOVEDOWN: MoveMenuItem(hmenu, uPos, uPos + 2); break; } DestroyMenu(hmenuPopup); } } } HANDLE_MSG(hwnd, WM_MENURBUTTONUP, OnMenuRButtonUp); // InitApp function wc.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN);
When we receive the WM_MENURBUTTONUP message and confirm that the menu is the one we support, we create the popup menu and display it at the mouse location (obtained via GetMessagePos) with the TPM_RECURSE flag, indicating that this is a pop-up menu for a pop-up menu. (We also use TPM_RETURNCMD, but that's nothing new.) If the user chose to move the item up or down, we move it up or down.
GetMessagePos
TPM_RETURNCMD
That's all. There really isn't much here, but I figured I'd just write a sample program just to show how it's done.