{"id":26083,"date":"2007-07-10T10:00:00","date_gmt":"2007-07-10T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/07\/10\/the-forgotten-common-controls-the-showhidemenuctl-function\/"},"modified":"2007-07-10T10:00:00","modified_gmt":"2007-07-10T10:00:00","slug":"the-forgotten-common-controls-the-showhidemenuctl-function","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070710-00\/?p=26083","title":{"rendered":"The forgotten common controls: The ShowHideMenuCtl function"},"content":{"rendered":"<p>\nThe <code>ShowHideMenuCtl<\/code> function is one of those\nfunctions everybody tries to pretend doesn&#8217;t exist.\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/06\/08\/622194.aspx\">\nYou thought <code>MenuHelp<\/code> was bad<\/a>;\n<code>ShowHideMenuCtl<\/code> is even worse.\n<\/p>\n<p>\nThe idea behind <code>ShowHideMenuCtl<\/code> was that you\nhad a window with a menu as well as controls,\nand some of the menu items were checkable,\nindicating whether the corresponding control should be shown.\nFor example, on your View menu you might have options\nnamed Toolbar or Status Bar.\nIf the user checks Toolbar, then the toolbar is shown in the main window;\nif the user unchecks Toolbar, then the toolbar is hidden.\n<\/p>\n<p>\nThe parameters to the <code>ShowHideMenuCtl<\/code> function are\na window (the window on which you want to operate),\na menu identifier (the menu item you wish to toggle),\nand a mysterious array of integers.\nEverything hangs on that mysterious array of integers,\nwhich takes the following form (expressed in pseudo-C):\n<\/p>\n<pre>\nstruct MENUCONTROLINTS {\n int idMenu;\n int idControl;\n};\nstruct SHOWHIDEMENUCONTROLINTS {\n int idMainMenu;\n HMENU hmenuMain;\n MENUCONTROLINTS rgwMenuControl[];\n};\n<\/pre>\n<p>\nThe <code>MENUCONTROLINTS<\/code> structure is easier to describe.\nIt merely establishes the correspondence between a menu item and\nthe control that will be shown or hidden.\n(Exercise: Why do we need two integers?\nWhy can&#8217;t we just give the menu item and the control the same ID?)\nThe array of <code>MENUCONTROLINTS<\/code> structures is terminated\nby a pair whose <code>idMenu<\/code> is zero.\n<\/p>\n<p>\nThe tricky bit is the first two entries,\n<code>idMainMenu<\/code> and <code>hmenuMain<\/code>.\nThe <code>hmenuMain<\/code> is the handle to the main menu for\nthe window, and\nthe <code>idMainMenu<\/code> is the item on the menu corresponding\nto the &#8220;Hide menu&#8221; entry on the main menu.\n(That&#8217;s why <code>hmenuMain<\/code> need to be passed explicitly.\nWe would normally use <code>GetMenu(hwnd)<\/code> to get the handle\nto the main menu, but if we&#8217;ve removed it, then <code>GetMenu(hwnd)<\/code>\nwill return <code>NULL<\/code>.)\nIf you don&#8217;t want to have a &#8220;Hide menu&#8221; option,\nyou can just put a dummy value in the <code>idMainMenu<\/code> slot\nthat doesn&#8217;t correspond to any menu item.\n(The value <code>-1<\/code> is probably most convenient for this.\nDon&#8217;t use zero since it terminates the list!)\n<\/p>\n<p>\nWhen you call the <code>ShowHideMenuCtl<\/code> function,\nit searches for the menu item you specified and toggles the\ncheck mark next to that item.\nWhat happens next depends on what type of item was found.\n<\/p>\n<ul>\n<li>If the item is <code>idMainMenu<\/code>, then the main menu is\nattached to or removed from the window (by using the\n<code>SetMenu<\/code> function, of course),\ncorresponding to the check box.<\/p>\n<li>If the item is <code>idMenu<\/code>, then the corresponding\ncontrol is shown or hidden (by using the <code>ShowWindow<\/code>\nfunction, of course),\ncorresponding to the check box.\n<\/ul>\n<p>\nThat&#8217;s all there is to it.\nThe rest is up to you.\nFor example, when a control is shown or hidden,\nit&#8217;s still up to your program to relayout the visible controls\nto account for the new window visibility state.\nFor example, if the user shows the toolbar,\nthen the other controls need to move out of the way to make room\nfor the toolbar.\nThe <code>ShowHideMenuCtl<\/code> function can&#8217;t do this for you\nsince it has no idea what your window layout is.\n<\/p>\n<p>\nLet&#8217;s put this information into practice.\nStart with our\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/a>\nand make the following changes;\n<\/p>\n<pre>\nHMENU g_hmenuMain;\nINT rgiMenu[] = {\n    100, 0,\n    101, 200,\n    0, 0,\n};\nBOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n    \/* We'll talk about this line more later *\/\n    rgiMenu[1] = (INT)GetMenu(hwnd);\n    CreateWindow(TEXT(\"Button\"), TEXT(\"Sample\"),\n                 WS_CHILD | BS_PUSHBUTTON, 0, 0, 100, 100,\n                 hwnd, IntToPtr_(HMENU, 200), g_hinst, 0);\n    return TRUE;\n}\nvoid\nOnDestroy(HWND hwnd)\n{\n    if (!GetMenu(hwnd))\n        DestroyMenu(IntToPtr_(HMENU, rgiMenu[1]));\n    PostQuitMessage(0);\n}\nvoid OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)\n{\n    switch (id) {\n    case 100:\n    case 101: ShowHideMenuCtl(hwnd, id, rgiMenu); break;\n    }\n}\nHANDLE_MSG(hwnd, WM_COMMAND, OnCommand);\nBOOL\nInitApp(void)\n{\n    ....\n    wc.lpszMenuName = <font COLOR=\"blue\">MAKEINTRESOURCE(1)<\/font>;\n    ....\n}\n\/* add to resource file *\/\n1 MENU PRELOAD\nBEGIN\n    POPUP \"&amp;View\"\n    BEGIN\n        MENUITEM \"&amp;Menu Bar\", 100, CHECKED\n        MENUITEM \"&amp;Button\", 101\n    END\nEND\n<\/pre>\n<p>\nMost of the changes are just setting up.\nWe attach a menu to our window with two options,\none to hide and show the menu bar,\nand one to hide and show our custom button.\nSince our window starts out with the menu bar visible\nand the button hidden, our menu template checks the\n&#8220;Menu Bar&#8221; item but not the &#8220;Button&#8221; one.\n<\/p>\n<p>\nThe <code>OnCreate<\/code> function finishes setting up up the\n<code>rgiMenu<\/code> array\nby putting the main menu&#8217;s handle into index&nbsp;1 in the\narray of integers,\nwhich corresponds to <code>hmenuMain<\/code> in our pseudo-structure.\nThe <code>OnDestroy<\/code> function destroys the menu if it isn&#8217;t\nattached to the window,\nsince\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/12\/30\/46594.aspx\">\nmenus attached to a window are destroyed automatically when the\nwindow is destroyed<\/a>.\nThe magic happens in the <code>OnCommand<\/code> handler.\nIf the user picked one of our two menu items, then we ask\n<code>ShowHideMenuCtl<\/code> to hide and show the button or menu.\n<\/p>\n<p>\nThe tricky bit is setting up our <code>rgiMenu<\/code>.\nLet&#8217;s break down those integers.\n<\/p>\n<table BORDER=\"1\">\n<tr>\n<td>100<\/td>\n<td>Menu identifier for hiding and showing the menu bar<\/td>\n<\/tr>\n<tr>\n<td>0<\/td>\n<td>Placeholder\n        (receives main menu handle in <code>OnCreate<\/code> handler)<\/td>\n<\/tr>\n<tr>\n<td>101<\/td>\n<td>Menu identifier for hiding and showing the menu bar<\/td>\n<\/tr>\n<tr>\n<td>200<\/td>\n<td>Control ID for the button that is shown and hidden\n        (passed to the <code>CreateWindow<\/code> function)<\/td>\n<\/tr>\n<tr>\n<td>0, 0<\/td>\n<td>List terminator<\/td>\n<\/tr>\n<\/table>\n<p>\nWhen you run this program,\nyou can use the &#8220;Button&#8221; menu option to hide and show the button,\nand you can use the &#8220;Menu Bar&#8221; menu option to hide and show the window&#8217;s\nmain menu.\nErm, no wait, you can&#8217;t use it to show\nthe main menu, because the main menu is hidden!\nNaturally, if your program uses the ability to hide the main menu,\nyou need to provide some alternate mechanism for bringing the\nmain menu back,\nsay via a hotkey or by adding an option to the System menu.\n<\/p>\n<p>\nOkay, now back to that line in the <code>OnCreate<\/code> function\nthat I promised to talk about.\nIf you have been paying attention, alarm bells should have gone off\nin your head at the line\n<code>rgiMenu[1] = (INT)GetMenu(hwnd);<\/code>\nbecause we are casting an <code>HMENU<\/code> to an integer.\nOn 64-bit machines, a <code>HMENU<\/code> is a 64-bit value,\nbut integers are only 32-bit.\nThis cast truncates the handle value and consequently is not\n64-bit safe.\nSince the <code>ShowHideMenuCtl<\/code> function requires an\narray of integers, you&#8217;re stuck.\nYou can&#8217;t shove a 64-bit menu handle into a 32-bit integer.\nThe <code>ShowHideMenuCtl<\/code> function is fundamentally flawed;\nit is not 64-bit compatible.\n<\/p>\n<p>\nFortunately, nobody uses the <code>ShowHideMenuCtl<\/code>\nfunction anyway.\nIts functionality is so simple, most programs have already\nwritten a function that does roughly the same thing,\nand since you have to write the layout code anyway,\nthe <code>ShowHideMenuCtl<\/code> function doesn&#8217;t really\nsave you very much effort anyway.\nLike <code>MenuHelp<\/code>,\nthe function is entirely vestigial and isn&#8217;t something\nyou should be tempted to use in any modern program.\nIt&#8217;s a leftover from the days of 16-bit Windows.\n<\/p>\n<p>\nWhy does such a confusing function exist at all?\nWell, the shell team thought they were doing you a favor\nby providing this function back in the 16-bit days.\nThis was originally an internal function used by\n(I think it was) File Manager,\nbut since it solved a more general problem,\nthe function was exported and documented.\nIn the intervening years,\nthe problem it addressed has been solved in other ways,\nand the introduction of 64-bit Windows rendered the original\nsolution unworkable anyway,\nbut the function and the code behind it must still linger\nin the system for backwards compatibility purposes.\n<\/p>\n<p>\nThe shell team learned its lesson.\nIt no longer exports every little helper function and custom control\nfor third parties to use.\nIf a future version of Windows no longer needs the helper function,\nor if a redesign of Windows Explorer removes the need for that\ncustom control (or worse, changes the behavior of that custom control),\nthe shell would still have to carry all the code around for the\nunused function or control\nbecause a function, once documented, becomes a continuing support burden.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The ShowHideMenuCtl function is one of those functions everybody tries to pretend doesn&#8217;t exist. You thought MenuHelp was bad; ShowHideMenuCtl is even worse. The idea behind ShowHideMenuCtl was that you had a window with a menu as well as controls, and some of the menu items were checkable, indicating whether the corresponding control should be [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-26083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The ShowHideMenuCtl function is one of those functions everybody tries to pretend doesn&#8217;t exist. You thought MenuHelp was bad; ShowHideMenuCtl is even worse. The idea behind ShowHideMenuCtl was that you had a window with a menu as well as controls, and some of the menu items were checkable, indicating whether the corresponding control should be [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/26083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=26083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/26083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=26083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=26083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=26083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}