Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Windows Menus and the WM_MENUCOMMAND message

Windows Menus and the WM_MENUCOMMAND message

Scheduled Pinned Locked Moved C / C++ / MFC
questionc++csstoolsjson
7 Posts 2 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Martin0815
    wrote on last edited by
    #1

    Hello, I'm working with/on an application with a resource based menu. This application is more or less driven by the programming (script) language tcl and has a lot of APIs introducing C++ functionality to tcl. Now I built an API to manage (popup) menus and their menu items, to create new items with tcl script callbacks, etc. The main point in my "construct" is to use a template menu item from a template menu resource. I created a menu in the resources as template containing a menu item as template. Everything was fine until I realized, that I seemed to have no chance to differentiate between the new commands having all the same id, but different application defined data - changed via the MENUITEMINFO and the related functions Get/SetMenuItemInfo. I changed the menus after their creation to send a WM_MENUCOMMAND message instead of a WM_COMMAND message by setting the dwStyle flag MNS_NOTIFYBYPOS inside the MENUINFO structure via a call to SetMenuInfo. Now - finally to the problem and the question - why I never receive the WM_MENUCOMMAND message? I patched CMainFrame::PreTranslateMessage method to catch the WM_MENUCOMMAND message, I tried with CMainFrame::WindowProc, and by registering a ON_MESSAGE handler inside the message map, but ... nothing worked! Thanks for any reaction in advance! Best regards, Martin Lemburg

    P 1 Reply Last reply
    0
    • M Martin0815

      Hello, I'm working with/on an application with a resource based menu. This application is more or less driven by the programming (script) language tcl and has a lot of APIs introducing C++ functionality to tcl. Now I built an API to manage (popup) menus and their menu items, to create new items with tcl script callbacks, etc. The main point in my "construct" is to use a template menu item from a template menu resource. I created a menu in the resources as template containing a menu item as template. Everything was fine until I realized, that I seemed to have no chance to differentiate between the new commands having all the same id, but different application defined data - changed via the MENUITEMINFO and the related functions Get/SetMenuItemInfo. I changed the menus after their creation to send a WM_MENUCOMMAND message instead of a WM_COMMAND message by setting the dwStyle flag MNS_NOTIFYBYPOS inside the MENUINFO structure via a call to SetMenuInfo. Now - finally to the problem and the question - why I never receive the WM_MENUCOMMAND message? I patched CMainFrame::PreTranslateMessage method to catch the WM_MENUCOMMAND message, I tried with CMainFrame::WindowProc, and by registering a ON_MESSAGE handler inside the message map, but ... nothing worked! Thanks for any reaction in advance! Best regards, Martin Lemburg

      P Offline
      P Offline
      prasad_som
      wrote on last edited by
      #2

      Can you provide code ? how you are creating menu, using SetMenuInfo etc. ?

      Prasad Notifier using ATL | Operator new[],delete[][^]

      M 1 Reply Last reply
      0
      • P prasad_som

        Can you provide code ? how you are creating menu, using SetMenuInfo etc. ?

        Prasad Notifier using ATL | Operator new[],delete[][^]

        M Offline
        M Offline
        Martin0815
        wrote on last edited by
        #3

        Yes - here's some "reduced" code: 1. the creation of a popup menu:

        DWORD       style       = 0;
        CMenu       \*popup      = (CMenu \*) NULL;
        MENUINFO    menuInfo;   // see below (1)
        
        memset( &menuInfo, 0x0, sizeof( MENUINFO ) );   // (1)
        
        // create the new menu object
        //
        popup   = new CMenu();
        
        // create the new popup menu
        //
        if ( ( popup != NULL ) && ( popup->CreatePopupMenu() == TRUE ) )
        {
            // initialize the menu info structure to get its dwStyle member
            //
            menuInfo.cbSize = sizeof( MENUINFO );
            menuInfo.fMask  = MIM\_STYLE;
        
            if ( popup->GetMenuInfo( &menuInfo ) == TRUE )
            {
                style   = menuInfo.dwStyle;
        
                // (re)initialize the menu info structure to change only its dwStyle member
                //
                memset( &menuInfo, 0x0, sizeof( MENUINFO ) );
        
                menuInfo.cbSize     = sizeof( MENUINFO );
                menuInfo.fMask      = MIM\_APPLYTOSUBMENUS | MIM\_STYLE;
                menuInfo.dwStyle    = style | MNS\_NOTIFYBYPOS;
        
                if ( popup->SetMenuInfo( &menuInfo ) == TRUE )
                {
                    tcl\_publishResult( ip, (char \*) create\_popup\_token( popup ) );
                    return TCL\_OK;
                }
            }
        }
        
        system\_error\_message( ip, "couldn't create popup menu" );
        
        if ( popup != NULL )
        {
            delete popup;
        }
        
        return TCL\_ERROR;
        

        2. the insertion of a created popup menu:

        int             itemPosition    = 0;
        char            \*label          = (char \*) NULL;
        CWnd            \*root           = (CWnd \*) NULL;
        CMenu           \*menu           = (CMenu \*) NULL,
                        \*popup          = (CMenu \*) NULL;
        MENUITEMINFO    menuInfo;       // see below (1)
        
        Menu\_if\_tcl\_MenuItem\_s\_t    \*menuItem   = (Menu\_if\_tcl\_MenuItem\_s\_t \*) NULL;
        
        memset( &menuInfo, 0x0, sizeof( MENUITEMINFO ) );   // (1)
        
        menuInfo.cbSize = sizeof( MENUITEMINFO );
        
        // get the popup menu pointer and the label ...
        //
        // ...
        //
        
        // access the main window
        //
        root    = AfxGetApp()->m\_pMainWnd;
        menu    = get\_owning\_menu( ip, root->GetMenu(), positionsList, itemPosition );
        
        if ( ( menu != NULL ) &&
             ( itemPosition != -1 ) &&
             ( (UINT) itemPosition <= menu->GetMenuItemCount() ) )
        {
            if ( menu->InsertMenu( itemPosition, MF\_BYPOSITION | MF\_STRING | MF\_POPUP, (UINT) popup->m\_hMenu, label ) == TRUE )
        
        P 1 Reply Last reply
        0
        • M Martin0815

          Yes - here's some "reduced" code: 1. the creation of a popup menu:

          DWORD       style       = 0;
          CMenu       \*popup      = (CMenu \*) NULL;
          MENUINFO    menuInfo;   // see below (1)
          
          memset( &menuInfo, 0x0, sizeof( MENUINFO ) );   // (1)
          
          // create the new menu object
          //
          popup   = new CMenu();
          
          // create the new popup menu
          //
          if ( ( popup != NULL ) && ( popup->CreatePopupMenu() == TRUE ) )
          {
              // initialize the menu info structure to get its dwStyle member
              //
              menuInfo.cbSize = sizeof( MENUINFO );
              menuInfo.fMask  = MIM\_STYLE;
          
              if ( popup->GetMenuInfo( &menuInfo ) == TRUE )
              {
                  style   = menuInfo.dwStyle;
          
                  // (re)initialize the menu info structure to change only its dwStyle member
                  //
                  memset( &menuInfo, 0x0, sizeof( MENUINFO ) );
          
                  menuInfo.cbSize     = sizeof( MENUINFO );
                  menuInfo.fMask      = MIM\_APPLYTOSUBMENUS | MIM\_STYLE;
                  menuInfo.dwStyle    = style | MNS\_NOTIFYBYPOS;
          
                  if ( popup->SetMenuInfo( &menuInfo ) == TRUE )
                  {
                      tcl\_publishResult( ip, (char \*) create\_popup\_token( popup ) );
                      return TCL\_OK;
                  }
              }
          }
          
          system\_error\_message( ip, "couldn't create popup menu" );
          
          if ( popup != NULL )
          {
              delete popup;
          }
          
          return TCL\_ERROR;
          

          2. the insertion of a created popup menu:

          int             itemPosition    = 0;
          char            \*label          = (char \*) NULL;
          CWnd            \*root           = (CWnd \*) NULL;
          CMenu           \*menu           = (CMenu \*) NULL,
                          \*popup          = (CMenu \*) NULL;
          MENUITEMINFO    menuInfo;       // see below (1)
          
          Menu\_if\_tcl\_MenuItem\_s\_t    \*menuItem   = (Menu\_if\_tcl\_MenuItem\_s\_t \*) NULL;
          
          memset( &menuInfo, 0x0, sizeof( MENUITEMINFO ) );   // (1)
          
          menuInfo.cbSize = sizeof( MENUITEMINFO );
          
          // get the popup menu pointer and the label ...
          //
          // ...
          //
          
          // access the main window
          //
          root    = AfxGetApp()->m\_pMainWnd;
          menu    = get\_owning\_menu( ip, root->GetMenu(), positionsList, itemPosition );
          
          if ( ( menu != NULL ) &&
               ( itemPosition != -1 ) &&
               ( (UINT) itemPosition <= menu->GetMenuItemCount() ) )
          {
              if ( menu->InsertMenu( itemPosition, MF\_BYPOSITION | MF\_STRING | MF\_POPUP, (UINT) popup->m\_hMenu, label ) == TRUE )
          
          P Offline
          P Offline
          prasad_som
          wrote on last edited by
          #4

          The problem , I see in your code is, you have applied MENUINFO, before inserting menu and submenus. I tried on simple SDI application, creating a pop - up menu in resource, and using SetMenuInfo . It work like charm.

          Prasad Notifier using ATL | Operator new[],delete[][^]

          M 1 Reply Last reply
          0
          • P prasad_som

            The problem , I see in your code is, you have applied MENUINFO, before inserting menu and submenus. I tried on simple SDI application, creating a pop - up menu in resource, and using SetMenuInfo . It work like charm.

            Prasad Notifier using ATL | Operator new[],delete[][^]

            M Offline
            M Offline
            Martin0815
            wrote on last edited by
            #5

            Hello Prasad, thanks for your engagement! I changed my sources, so that ... 1. no MENUINFO action happens while creating the popup 2. the insertion is slightly changed: 2.1 menu->InsertMenu( itemPosition, ..., popup->m_hMenu, ... ) 2.2 popup = menu->GetSubMenu( itemPosition ) 2.3 requesting with popup->GetMenuInfo the MENUINFO to get the current dwStyle member => oldStyle 2.4 changing and setting with popup->SetMenuInfo the MENUINFO with dwStyle = oldStyle | MNS_NOTIFYBYPOS I have introduced the ON_MESSAGE handler for WM_MENUCOMMAND, extended the CMainFrame::WindowProc and the CMainFrame::PreTranslateMessage, but none of them gets a WM_MENUCOMMAND message. Even if a CMainFrame instance is the owner of the menu I insert my popups in, can I really be sure, that CMainFrame instance really receives the WM_MENUCOMMAND messages? Thanks again and best regards, Martin Lemburg

            P 1 Reply Last reply
            0
            • M Martin0815

              Hello Prasad, thanks for your engagement! I changed my sources, so that ... 1. no MENUINFO action happens while creating the popup 2. the insertion is slightly changed: 2.1 menu->InsertMenu( itemPosition, ..., popup->m_hMenu, ... ) 2.2 popup = menu->GetSubMenu( itemPosition ) 2.3 requesting with popup->GetMenuInfo the MENUINFO to get the current dwStyle member => oldStyle 2.4 changing and setting with popup->SetMenuInfo the MENUINFO with dwStyle = oldStyle | MNS_NOTIFYBYPOS I have introduced the ON_MESSAGE handler for WM_MENUCOMMAND, extended the CMainFrame::WindowProc and the CMainFrame::PreTranslateMessage, but none of them gets a WM_MENUCOMMAND message. Even if a CMainFrame instance is the owner of the menu I insert my popups in, can I really be sure, that CMainFrame instance really receives the WM_MENUCOMMAND messages? Thanks again and best regards, Martin Lemburg

              P Offline
              P Offline
              prasad_som
              wrote on last edited by
              #6

              Hi Martin, You must be using TrackPopupMenu for invoking pop up menu, isn't it ? Now, I'll tell you ,steps I followed to got it working. 1. Create a menu in resource editor with pop-up style. 2. Use CMenu::LoadMenu to load that menu. 3. Use SetMenuInfo as described in your original post. 4. Use TrackPopupMenu , set its parent as main frame window. 5. Override DefWndProc of CMainFrame(or you can use PreTranslateMessage). 6. I can see WM_MENUCOMMAND sent when clicked this menu. May this give you some idea.

              Prasad Notifier using ATL | Operator new[],delete[][^]

              M 1 Reply Last reply
              0
              • P prasad_som

                Hi Martin, You must be using TrackPopupMenu for invoking pop up menu, isn't it ? Now, I'll tell you ,steps I followed to got it working. 1. Create a menu in resource editor with pop-up style. 2. Use CMenu::LoadMenu to load that menu. 3. Use SetMenuInfo as described in your original post. 4. Use TrackPopupMenu , set its parent as main frame window. 5. Override DefWndProc of CMainFrame(or you can use PreTranslateMessage). 6. I can see WM_MENUCOMMAND sent when clicked this menu. May this give you some idea.

                Prasad Notifier using ATL | Operator new[],delete[][^]

                M Offline
                M Offline
                Martin0815
                wrote on last edited by
                #7

                Ok - got it working - a bit different than you told me to, and with a lot of consequences. The current state: 1. we have a MFC application 2. our MFC application has a resource based menu, with one ON_COMMAND handler per menu item 3. I wrote a tcl API to access the MFC application menu, which allows to create new sub menus and menu items. 4. before I insert a popup menu, I switch the MFC application menu MENUINFO to MNS_NOTIFYBYPOS, so that WM_MENUCOMMAND messages are used, instead of WM_COMMAND messages 5. after inserting a popup menu, I switch the new sub menu to use WM_MENUCOMMAND messages 6. I registered a ON_MESSAGE handler for WM_MENUCOMMAND messages The consequences: 1. None of the resource based menu items, with ON_COMMAND handlers, will work anymore, because there are no WM_COMMAND messages anymore 2. every selected menu item causes the wanted WM_MENUCOMMAND message 3. every menu in the "path" of (sub)menus seem to have this MENUINFO style flag MNS_NOTIFYBYPOS, so that this model is really working. If I don't switch all containing menus of a sub menus to send WM_MENUCOMMAND messages, than the whole model won't work. The suggestion above to use TrackPopupMenu must work, if the popup menu is used all alone, but if it is used inside a "path" of cascaded menus, than this would be more problematic. 4. the whole menu system of ON_COMMAND handlers must be rewritten, or I must find a way to get rid of the dummy or template menu item and create resources on the fly, but ... I don't know how! A change of question: How do I create on-the-fly resources or menu items with new, non-existing IDs? If I'd know, how to create on-the-fly resources, than I could stay with the normal WM_COMMAND system. Thanks to you Prasad! Best regards, and a happy weekend! Martin Lemburg

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups