HOWTO: Mirror Main Menu with TrackPopupMenu()

ID: Q99806

The information in this article applies to:

SUMMARY

A developer may want to use TrackPopupMenu() to display the same menu that is used by the main window. TrackPopupMenu() takes a pop-up menu, while GetMenu() and LoadMenu() both return handles to top level menus, and therefore you cannot use the menus returned from these functions with TrackPopupMenu(). To "mirror" the main menu, you must create pop-up menus with the same strings, style, and IDs as the main menu. To do this, use the following Windows APIs:

   GetMenu()
   CreatePopupMenu()
   GetMenuState()
   GetMenuString()
   GetSubMenu()
   AppendMenu()

MORE INFORMATION

The following code displays the same menu as the main window when the The user right-clicks:

   // In the main window procedure...

       case WM_RBUTTONDOWN:
       {

              HMENU hMenu;         // The handle to the main menu.
              int nMenu;           // The index of the menu item.
              POINT pt;            // The point to display the track menu.
              HMENU hMenuOurs;     // The pop-up menu that we are creating.
              UINT nID;            // The ID of the menu.
              UINT uMenuState;     // The menu state.
              HMENU hSubMenu;      // A submenu.
              char szBuf[128];     // A buffer to store the menu string.

   // Get the main menu.
              hMenu = GetMenu(hWnd);
              nMenu = 0;

   // Create a pop-up menu.
              hMenuOurs = CreatePopupMenu();

   // Get menu state returns the style of the menu
   // in the lobyte of the unsigned int. Return value
   // of -1 indicates the menu does not exist, and you
   // have finished creating your pop-up menu.
              while ((uMenuState =
                 GetMenuState(hMenu,nMenu,MF_BYPOSITION)) != -1)
              {
                   if (uMenuState != -1)
                   {
   // Get the menu string.
                 GetMenuString(hMenu,nMenu, szBuf,128,MF_BYPOSITION);
                       if (LOBYTE(uMenuState) & MF_POPUP) // Pop-up menu.
                       {
                           hSubMenu = GetSubMenu(hMenu,nMenu);
                              AppendMenu(hMenuOurs,
                       LOBYTE(uMenuState),hSubMenu,szBuf);
                       }
                       else  // Is a menu item, get the ID.
                       {
                           nID = GetMenuItemID(hMenu,nMenu);
                           AppendMenu(hMenuOurs,LOBYTE
                                      (uMenuState),nID,szBuf);

                       }
                       nMenu++;  // Get the next item.
                   }
           }
           pt = MAKEPOINT(lParam);
   // TrackPopupMenu expects screen coordinates.
           ClientToScreen(hWnd,&pt);
              TrackPopupMenu(hMenuOurs,
             TPM_LEFTALIGN|TPM_RIGHTBUTTON,
             pt.x,pt.y,0,hWnd,NULL);

   // Because you are using parts of the main menu in our
   // pop-up menu, you cannot just delete the pop-up menu without also
   // deleting the main menu. You must go through the pop-up menu and
   // remove all the items.
           while (RemoveMenu(hMenuOurs,0,MF_BYPOSITION))
               ;

   // Destroy the pop-up menu.
           DestroyMenu(hMenuOurs);
       }
       break;

If the menu is never dynamically modified, then the menu hMenuOurs could be made static and created inside the WM_CREATE message, and destroyed in the WM_DESTROY message.

To see how this function works, paste this code into the MENU sample application shipped with both Microsoft Visual C/C++ and Microsoft C/C++ version 7.0 in the file MENU.C in the MenuWndProc() function.

Additional query words: popup

Keywords          : kbcode kbMenu kbNTOS350 kbNTOS351 kbNTOS400 kbWinOS2000 kbGrpUser kbWinOS95 kbWinOS98 
Issue type        : kbhowto

Last Reviewed: December 24, 1998