Microsoft KB Archive/105169

{|
 * width="100%"|

Building a Dynamic Menu for TrackPopupMenu

 * }

Q105169

-

The information in this article applies to:


 * The Microsoft Foundation Classes (MFC), included with:
 * Microsoft Visual C++, versions 1.0, 1.5, 1.51, 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 query words: kbinf 1.00 1.50 2.00 2.50 popup pop up

Keywords : kb16bitonly

Issue type :

Technology : kbAudDeveloper kbMFC