Building a Dynamic Menu for TrackPopupMenu

Last reviewed: July 22, 1997
Article ID: Q105169
1.00 1.50 1.51 1.52 WINDOWS kbprg

The information in this article applies to:

  • The Microsoft Foundation Classes (MFC) included with: Microsoft Visual C++ for Windows, versions 1.0, 1.5, 1.51, and 1.52

SUMMARY

In most cases, a menu to be used in the call to TrackPopupMenu can be created at design time using the App Studio. However, when the menu items are dynamic and not known until run time, it is necessary to build the menu from scratch using the CMenu member functions.

Due to the way the Microsoft Foundation Classes (MFC) implements the CMenu class, combined with the way Windows deletes menu resources, potential problems can occur when the CMenu object's destructor is called. Specifically, the destructor calls ::DeleteMenu() to delete the Windows menu resource. If the pop-up menu contains other pop-up menus (known as cascading menus), these menus must be detached using the CMenu::Detach() function. These menus should be detached before the top level CMenu object is destroyed. Failure to Detach() the cascading pop-up menus causes the debugging kernel of Windows to generate the error "Invalid HMENU: FatalExit code = 0x6041".

MORE INFORMATION

Suppose the pop-up menu has the following items:

   Apples
   Pears
   Grapes
   Other Misc. Fruit >
                     Mangos
                     Tomatoes

To build this menu at run time, the following code may be used:

   CMenu MainTPMMenu;
   CMenu MiscFruitMenu;

   MainTPMMenu.CreatePopupMenu();
   MainTPMMenu.AppendMenu(MF_STRING | MF_ENABLED, 42, "Apples");
   MainTPMMenu.AppendMenu(MF_STRING | MF_ENABLED, 43, "Pears");
   MainTPMMenu.AppendMenu(MF_STRING | MF_ENABLED, 43, "Grapes");
   MiscFruitMenu.CreatePopupMenu();
   MiscFruitMenu.AppendMenu(MF_STRING | MF_ENABLED, 40, "Mangos");
   MiscFruitMenu.AppendMenu(MF_STRING | MF_ENABLED, 41, "Tomatoes");
   MainTPMMenu.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
                          (UINT)MiscFruitMenu.m_hMenu,
                          "Other Misc. Fruit");
   MainTPMMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x,
                              pt.y, this, NULL);

On the surface, this code appears fine. However, a FatalExit can occur under the debug kernel of Windows.

When an application calls ::DeleteObject() to delete a menu resource, Windows looks at the menu and determines whether it contains any cascading pop-up menus. If so, Windows deletes the menu resource associated with the cascading pop-up menu.

Now consider the following: when a CMenu object's destructor is called, the menu handle associated with the CMenu is deleted from the GDI heap using ::DeleteObject(). This leads to the problem. In the above example, if MainTPMMenu is destroyed first, Windows will look at the hMenu and determine that it has an associated cascading pop-up menu. Windows then deletes the hMenu for this cascading pop-up menu. Now, the MiscFruitMenu object is destroyed and ::DeleteObject() is called to delete the hMenu; however, the hMenu has already been deleted by Windows. This, of course, leads to the FatalExit.

The solution to this problem is to use CMenu::Detach() to detach any cascading pop-up menus. You should place the call to Detach() somewhere in your code such that it is executed BEFORE any of the CMenu objects are destroyed. In the above example, you could simply call MiscFruitMenu.Detach() after the call to TrackPopupMenu().


Additional reference words: kbinf 1.00 1.50 2.00 2.50 popup pop up
KBCategory: kbprg
KBSubcategory: MfcUI
Keywords : kb16bitonly
Technology : kbMfc


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 22, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.