{"id":21693,"date":"2008-07-09T07:00:00","date_gmt":"2008-07-09T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2008\/07\/09\/the-evolution-of-menu-templates-16-bit-classic-menus\/"},"modified":"2008-07-09T07:00:00","modified_gmt":"2008-07-09T07:00:00","slug":"the-evolution-of-menu-templates-16-bit-classic-menus","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080709-00\/?p=21693","title":{"rendered":"The evolution of menu templates: 16-bit classic menus"},"content":{"rendered":"<p><P>\nMenus aren&#8217;t as complicated as dialogs.\nThere are no fonts, no positioning,\nit&#8217;s just a list of menu items and flags.\nWell, okay, there&#8217;s the recursive part,\nwhen a menu has a submenu.\nBut that&#8217;s really the only wrinkle.\nMost of it is pretty boring.\n<\/P>\n<P>\nThe 16-bit classic menu template begins with the following header:\n<\/P>\n<PRE>\nstruct MENUHEADER16 {\n WORD wVersion;\n WORD cbHeaderSize;\n BYTE rgbExtra[cbHeaderSize];\n};\n<\/PRE>\n<P>\nThe version is zero for 16-bit classic menu templates,\nand the <CODE>cbHeaderSize<\/CODE> is the number of\nextra bytes in the menu header that have to be skipped over\nto find the first actual menu item.\nIn practice, <CODE>cbHeaderSize<\/CODE> is always zero.\nThis header exists only on the top level menu;\nrecursive submenus do not have a <CODE>MENUHEADER16<\/CODE>.\n<\/P>\n<P>\nAfter the header (and any extra bytes specified by <CODE>cbHeaderSize<\/CODE>)\ncomes a packed array of menu item templates.\nThere are two types of menu item templates, normal items and\npop-up submenus.\nFirst, let&#8217;s look at the normal items:\n<\/P>\n<PRE>\nstruct NORMALMENUITEM16 {\n WORD wFlags;       \/\/ menu item flags (MFT_*, MFS_*)\n WORD wID;          \/\/ menu item ID\n CHAR szText[];     \/\/ null terminated ANSI string\n};\n<\/PRE>\n<P>\nNormal items represent menu items that are not pop-up submenus,\nand they take a pretty straightforward form.\nAll you get are flags, the item ID, and the menu item text.\nThe flags are values such as\n<CODE>MFT_STRING<\/CODE>,\n<CODE>MFT_MENUBARBREAK<\/CODE>,\nand <CODE>MFS_DISABLED<\/CODE>.\nOf course, the <CODE>MF_POPUP<\/CODE> flag is not allowed,\nsince this is a normal item template.\nThe flag <CODE>MFS_HILITE<\/CODE> is also not allowed,\nfor reasons we will see later.\n<\/P>\n<P>\nThe other type of menu item template is the pop-up submenu.\n<\/P>\n<PRE>\nstruct POPUPMENUITEM16 {\n WORD wFlags;       \/\/ menu item flags (MFT_*, MFS_*)\n CHAR szText[];     \/\/ null terminated ANSI string\n};\n<\/PRE>\n<P>\nThe pop-up item template\ndoesn&#8217;t have an ID, the <CODE>MF_POPUP<\/CODE> flag\nmust be set in the flags (naturally),\nthe <CODE>MFS_HILITE<\/CODE> flag must not be set,\nand it is immediately followed by&#8230; another menu resource,\nminus the resource header, which describes the pop-up submenu itself.\n(This is the recursive part.)\n<\/P>\n<P>\nThe end of the list of menu item templates is reached\nwhen an item with the <CODE>MF_END<\/CODE> flag is set in its flags.\nAnd now you see why <CODE>MFS_HILITE<\/CODE> is disallowed:\n<\/P>\n<PRE>\n#define MF_END              0x00000080L\n#define MF_HILITE           0x00000080L\n#define MFS_HILITE          MF_HILITE\n<\/PRE>\n<P>\nIf you set the <CODE>MF_HILITE<\/CODE> flag,\nit would be mistaken for the end of the menu template.\nFortunately, there&#8217;s no need to set the <CODE>MFS_HILITE<\/CODE>\nflag in the menu item template since highlighting happens at runtime\nbased on the user&#8217;s mouse and keyboard activity,\nnot at menu creation time.\n<\/P>\n<P>\nTo make all this discussion concrete, let&#8217;s convert\nthis rather uninteresting menu resource into a menu template:\n<\/P>\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>\nThe menu template for this classic 16-bit menu would go something\nlike this:\nWe start with the header, which always looks the same.\n<\/P>\n<PRE>\n0000  00 00      \/\/ wVersion = 0\n0002  00 00      \/\/ cbHeaderSize = 0\n<\/PRE>\n<P>\nNext comes the list of menu items.\nOur first is a pop-up submenu,\nso the <CODE>MF_POPUP<\/CODE> flag is set,\nindicating that we have a <CODE>POPUPMENUITEM16<\/CODE>:\n<PRE>\n0004  10 00     \/\/ wFlags = MF_POPUP\n                \/\/ no wID\n0006  26 46 69 6C 65 00 \/\/ &#8220;&amp;File&#8221; + null terminator\n<\/PRE>\n<P>\nSince this is a pop-up menu, the contents of the pop-up menu\nfollow.\nThis is the recursive part of the menu template format:\nwe have a menu template inside the outer one.\nThe first item of the pop-up menu is a string and\ntherefore takes the form of a <CODE>NORMALMENUITEM16<\/CODE>:\n<\/P>\n<PRE>\n000C  00 00     \/\/ wFlags = MFT_STRING\n000E  64 00     \/\/ wID = 100\n0010  26 4F 70 65 6E 09 43 74 72 6C 2B 4F 00\n                \/\/ &#8220;&amp;Open\\tCtrl+O&#8221; + null terminator\n<\/PRE>\n<P>\nThe next item of the pop-up menu is a separator.\nIf you have been following the rules strictly,\nyou would generate the separator like this:\n<\/P>\n<PRE>\n001D  00 08     \/\/ wFlags = MFT_SEPARATOR\n001F  00 00     \/\/ wID = 0\n0021  00        \/\/ &#8220;&#8221;\n<\/PRE>\n<P>\nHowever, it turns out that there is an alternate form for\nseparators, namely to pass all zeroes:\n<\/P>\n<PRE>\n001D  00 00     \/\/ wFlags = 0\n001F  00 00     \/\/ wID = 0\n0021  00        \/\/ &#8220;&#8221;\n<\/PRE>\n<P>\nThe existence of this alternate form is actually an artifact\nof history, which we&#8217;ll look at next time.\nBut for now, just realize that you can express a separator\nin two different ways, either the official way with <CODE>MFT_SEPARATOR<\/CODE>\nor the alternate way with <CODE>wFlags = 0<\/CODE>.\nEither works just fine.\n<\/P>\n<P>\nAnyway, let&#8217;s finish up that submenu with the final item,\nwhich is a string.\nWe set the <CODE>MF_END<\/CODE> flag to indicate that this is\nthe end of the (nested) menu.\n<\/P>\n<PRE>\n0022  80 00    \/\/ wFlags = MFT_STRING | MF_END\n0024  65 00    \/\/ wID = 101\n0026  26 45 78 69 74 09 41 6C 74 2B 58 00\n               \/\/ &#8220;&amp;Exit\\tAlt+X&#8221; + null terminator\n<\/PRE>\n<P>\nWith the completion of the nested menu, we pop back to the\ntop-level menu.\nNext comes the &#8220;View&#8221; submenu.\n<\/P>\n<PRE>\n0032  90 00     \/\/ wFlags = MF_POPUP | MF_END\n                \/\/ no wID\n0034  26 56 69 65 77 00 \/\/ &#8220;&amp;View&#8221; + null terminator\n<\/PRE>\n<P>\nThe <CODE>MF_POPUP<\/CODE> flag marks this as a\n<CODE>POPUPMENUITEM16<\/CODE>, which means that there is no\n<CODE>wID<\/CODE>.\nAnd look, the <CODE>MF_END<\/CODE> flag is set,\nwhich means that this is the last item on the top-level\nmenu.\nBut we&#8217;re not finished yet, since we still have to read\nthe nested submenu.\n(Notice that the &#8220;end of menu&#8221; marker is far away from\nthe actual end of the menu!)\n<\/P>\n<PRE>\n003A  88 00    \/\/ wFlags = MFT_STRING | MFS_CHECKED | MF_END\n003C  66 00    \/\/ wID = 102\n003E  26 53 74 61 74 75 73 20 42 61 72 00\n                \/\/ &#8220;&amp;Status Bar&#8221; + null terminator\n<\/PRE>\n<P>\nThe submenu consists of a single item,\nso its first item is also its last (<CODE>MF_END<\/CODE>).\nNow that the submenu is complete, we pop back to the main menu again,\nbut as we saw, the main menu is also complete,\nso that concludes the entire menu template.\n<\/P>\n<P>\nNext time, we&#8217;ll look at that strange alternate form for\nseparator items before returning to the history of menu templates.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Menus aren&#8217;t as complicated as dialogs. There are no fonts, no positioning, it&#8217;s just a list of menu items and flags. Well, okay, there&#8217;s the recursive part, when a menu has a submenu. But that&#8217;s really the only wrinkle. Most of it is pretty boring. The 16-bit classic menu template begins with the following header: [&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-21693","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Menus aren&#8217;t as complicated as dialogs. There are no fonts, no positioning, it&#8217;s just a list of menu items and flags. Well, okay, there&#8217;s the recursive part, when a menu has a submenu. But that&#8217;s really the only wrinkle. Most of it is pretty boring. The 16-bit classic menu template begins with the following header: [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/21693","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=21693"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/21693\/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=21693"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=21693"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=21693"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}