{"id":21653,"date":"2008-07-11T10:00:00","date_gmt":"2008-07-11T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/07\/11\/the-evolution-of-menu-templates-32-bit-classic-menus\/"},"modified":"2008-07-11T10:00:00","modified_gmt":"2008-07-11T10:00:00","slug":"the-evolution-of-menu-templates-32-bit-classic-menus","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080711-00\/?p=21653","title":{"rendered":"The evolution of menu templates: 32-bit classic menus"},"content":{"rendered":"<p><P>\nNow that we&#8217;ve got a handle on\n<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/07\/09\/8711897.aspx\">\n16-bit classic menu templates<\/A>,\nwe can move on to the next evolutionary step,\nnamely 32-bit classic menu templates.\n<\/P>\n<P>\nThe 32-bit classic menu template is in fact nearly identical to the\n16-bit classic menu template.\nThe only change is that the menu text is now a Unicode string instead\nof an ANSI string.\nConsequently, the discussion below will be rather brief\nwhen there is nothing new being introduced.\n<\/P>\n<P>\nThe 32-bit classic menu template begins with the same header,\nand the fields have the same meaning.\n<\/P>\n<PRE>\nstruct MENUHEADER32 {\n WORD wVersion;\n WORD cbHeaderSize;\n BYTE rgbExtra[cbHeaderSize];\n};\n<\/PRE>\n<P>\nActually, there&#8217;s a bonus wrinkle:\nWhereas the <CODE>cbHeaderSize<\/CODE> is always zero in practice\nfor 16-bit menu templates, the 32-bit <CODE>cbHeaderSize<\/cODE>\n<I>must be<\/I> zero if you intend your menu template to be used\non the Windows&nbsp;95 series of Windows operating systems.\n<\/P>\n<P>\nWhy must the value be zero on Windows&nbsp;95?\nI just discovered this now doing the research for this series of\narticles.\nIt&#8217;s a bug in the code that converts between 32-bit and 16-bit resources!\nWhen converting from a 32-bit menu template to a 16-bit menu template,\nthe conversion code dutifully copies the <CODE>cbHeaderSize<\/CODE> and\nuses it to skip ahead in the 32-bit menu template, but it neglects\nto skip ahead the same amount in the 16-bit menu template.\nFortunately, nobody ever sets this value to anything other than zero,\nso the bug never manifests itself in practice.\n(I suspect I&#8217;m the first person ever to notice this bug.\nFirst, because nobody generates menu templates at runtime;\neverybody uses the resource compiler or some other tool,\nand those tools all set the field to zero.\nAnd second, because those extra bytes aren&#8217;t used for anything,\nso there&#8217;s no reason for the count to be nonzero.)\n<\/P>\n<P>\nEven if you don&#8217;t care about Windows&nbsp;95, the <CODE>cbHeaderSize<\/CODE>\nmust still be an even number so that the menu item templates are suitably\naligned.\n<\/P>\n<P>\nThe rest of the 32-bit classic menu template is just stuff\nyou&#8217;ve seen before.\nWe have a packed array of menu item templates,\neither a <CODE>POPUPMENUITEM32<\/CODE> if the menu item is\na pop-up submenu, or a <CODE>NORMALMENUITEM32<\/CODE> if not:\n<\/P>\n<PRE>\nstruct NORMALMENUITEM32 {\n WORD wFlags;       \/\/ menu item flags (MFT_*, MFS_*)\n WORD wID;          \/\/ menu item ID\n WCHAR szText[];    \/\/ null terminated Unicode string\n};<\/p>\n<p>struct POPUPMENUITEM32 {\n WORD wFlags;       \/\/ menu item flags (MFT_*, MFS_*)\n WCHAR szText[];    \/\/ null terminated UNICODE string\n};\n<\/PRE>\n<P>\nAside from changing <CODE>CHAR<\/CODE> to <CODE>WCHAR<\/CODE>,\neverything is exactly the same.\nLet&#8217;s use that same resource script we used to illustrate\nthe 16-bit classic menu template and convert it to a 32-bit\nclassic menu template instead.\n<PRE>\n1 MENU\nBEGIN\n  POPUP &#8220;&amp;File&#8221;\n  BEGIN\n    MENUITEM &#8220;&amp;Open\\tCtrl+O&#8221;, 100\n    MENUITEM SEPARATOR\n    MENUITEM &#8220;&amp;Exit\\tAlt+X&#8221;,  101\n  END\n  POPUP &#8220;&amp;View&#8221;\n  BEGIN\n    MENUITEM &#8220;&amp;Status Bar&#8221;, 102, CHECKED\n  END\nEND\n<\/PRE>\n<P>\nCompiling this as a 32-bit classic menu template would result\nin something like this:\n<\/P>\n<PRE>\n\/\/ MENUHEADER32\n0000  00 00      \/\/ wVersion = 0\n0002  00 00      \/\/ cbHeaderSize = 0\n<\/PRE>\n<P>\nAfter the header come the top-level menu items:\n<\/P>\n<PRE>\n\/\/ POPUPMENUITEM32 for top-level menu\n0004  10 00     \/\/ wFlags = MF_POPUP\n                \/\/ no wID\n0006  26 00 46 00 69 00 6C 00 65 00 00 00\n                \/\/ &#8220;&amp;File&#8221; + null terminator\n<\/PRE>\n<P>\nSince we have a pop-up submenu, the contents of the\nsubmenu come next, and we put the top-level menu items on hold.\n<\/P>\n<PRE>\n\/\/ NORMALMENUITEM32 for nested menu\n0012  00 00     \/\/ wFlags = MFT_STRING\n0014  64 00     \/\/ wID = 100\n0016  26 00 4F 00 70 00 65 00 6E 00 09 00\n      43 00 74 00 72 00 6C 00 2B 00 4F 00 00 00\n                \/\/ &#8220;&amp;Open\\tCtrl+O&#8221; + null terminator\n<\/PRE>\n<P>\nFor the separator, we can either do it the formally correct way:\n<\/P>\n<PRE>\n\/\/ NORMALMENUITEM32 for nested menu &#8211; separator\n0030  00 08     \/\/ wFlags = MFT_SEPARATOR\n0032  00 00     \/\/ wID = 0\n0034  00 00     \/\/ &#8220;&#8221;\n<\/PRE>\n<P>\nor we can use the\n<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2008\/07\/10\/8714471.aspx\">\nalternate compatibility form<\/A>:\n<\/P>\n<PRE>\n0030  00 00     \/\/ wFlags = 0\n0032  00 00     \/\/ wID = 0\n0034  00 00     \/\/ &#8220;&#8221;\n<\/PRE>\n<P>\nThe last item on the submenu has the\n<CODE>MF_END<\/CODE> flag.\n<\/P>\n<PRE>\n\/\/ NORMALMENUITEM32 for nested menu &#8211; last item\n0036  80 00    \/\/ wFlags = MFT_STRING | MF_END\n0038  65 00    \/\/ wID = 101\n003A  26 00 45 00 78 00 69 00 74 00 09 00\n      41 00 6C 00 74 00 2B 00 58 00 00 00\n               \/\/ &#8220;&amp;Exit\\tAlt+X&#8221; + null terminator\n<\/PRE>\n<P>\nWe now pop back to the top-level menu, whos second item\nand final item is another pop-up submenu.\n<\/P>\n<PRE>\n\/\/ POPUPMENUITEM for top-level menu\n0052  90 00     \/\/ wFlags = MF_POPUP | MF_END\n                \/\/ no wID\n0054  26 00 56 00 69 00 65 00 77 00 00 00\n                \/\/ &#8220;&amp;View&#8221; + null terminator\n<\/PRE>\n<P>\nAnd finally, the contents of that last pop-up submenu.\n<\/P>\n<PRE>\n0060  88 00    \/\/ wFlags = MFT_STRING | MFS_CHECKED | MF_END\n0062  65 00    \/\/ wID = 102\n0064  26 00 53 00 74 00 61 00 74 00 75 00\n      73 00 20 00 42 00 61 00 72 00 00 00\n                \/\/ &#8220;&amp;Status Bar&#8221; + null terminator\n<\/PRE>\n<P>\nAnd that&#8217;s all there is to it.\nA pretty straightforward extension of the 16-bit classic\nmenu template to a 32-bit Unicode version.\n<P>\nAfter a short break, we&#8217;ll look at the extended menu templates.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Now that we&#8217;ve got a handle on 16-bit classic menu templates, we can move on to the next evolutionary step, namely 32-bit classic menu templates. The 32-bit classic menu template is in fact nearly identical to the 16-bit classic menu template. The only change is that the menu text is now a Unicode string instead [&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":[2],"class_list":["post-21653","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Now that we&#8217;ve got a handle on 16-bit classic menu templates, we can move on to the next evolutionary step, namely 32-bit classic menu templates. The 32-bit classic menu template is in fact nearly identical to the 16-bit classic menu template. The only change is that the menu text is now a Unicode string instead [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/21653","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=21653"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/21653\/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=21653"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=21653"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=21653"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}