{"id":38803,"date":"2004-06-18T06:58:00","date_gmt":"2004-06-18T06:58:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/06\/18\/the-evolution-of-dialog-templates-16-bit-classic-templates\/"},"modified":"2004-06-18T06:58:00","modified_gmt":"2004-06-18T06:58:00","slug":"the-evolution-of-dialog-templates-16-bit-classic-templates","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040618-00\/?p=38803","title":{"rendered":"The evolution of dialog templates &#8211; 16-bit Classic Templates"},"content":{"rendered":"<p>\nIn the history of Windows, there have been four versions of\ndialog templates.  And despite the changes, you&#8217;ll see that\nthey&#8217;re basically all the same.\n<\/p>\n<p>\nFirst, there was the classic Windows 1.0 dialog template.\nIt starts like this:\n<\/p>\n<pre>\nDWORD dwStyle; \/\/ dialog style\nBYTE  cItems;  \/\/ number of controls in this dialog\nWORD  x;       \/\/ x-coordinate\nWORD  y;       \/\/ y-coordinate\nWORD  cx;      \/\/ width\nWORD  cy;      \/\/ height\n<\/pre>\n<p>\nNotice that this is where the 255-controls-per-dialog\nlimit comes from on 16-bit Windows, since the field\nthat records the number of controls on the dialog is\nonly a byte.\n<\/p>\n<p>\nAfter this header come a series of strings.\nAll strings in the 16-bit dialog template\npermit a null-terminated ANSI string.\nFor example, if you wanted to store the string &#8220;Hello&#8221;,\nyou would write out the six bytes<\/p>\n<pre>\n48 65 6C 6C 6F 00  ; \"Hello\"\n<\/pre>\n<p>\n(As a special case of this: If you write out a single 00 byte,\nthen that represents a null string. Handy when you don&#8217;t\nactually want to store a string but the dialog format requires\nyou to store one.)\n<\/p>\n<p>\nSometimes you are allowed to specify a 16-bit ordinal value\ninstead of a string.  In that case, you write out the byte 0xFF\nfollowed by the ordinal.  For example, if you wanted to specify\nthe ordinal 42, you would write out the three bytes<\/p>\n<pre>\nFF 2A 00           ; FF followed by WORD (little-endian)\n<\/pre>\n<p>\nOkay, back to the dialog template.\nAfter the header, there are three strings:\n<\/p>\n<ul>\n<li>The menu name, which can be a string or an ordinal.\n    This is typically null, indicating that you don&#8217;t want a menu.\n    If non-null, then the menu will be loaded via LoadMenu\n    using the specified string or resource\n    from the instance handle passed to the dialog\n    creation function via the HINSTANCE parameter.<\/p>\n<li>The class, which must be a string (no ordinals allowed).\n    This is typically also null, indicating that\n    you want the default dialog class.\n    <a HREF=\"\/oldnewthing\/archive\/2003\/11\/13\/55662.aspx\">\n    We have seen earlier how you can override the\n    default dialog class to get special behavior<\/a>.\n    If non-null, the class will be also be looked up relative\n    to the instance handle passed to the dialog\n    creation function via the HINSTANCE parameter.<\/p>\n<li>The dialog title, which must be a string (no ordinals allowed).\n<\/ul>\n<p>\nIf the DS_SETFONT style is set, then what follows next is\na WORD indicating the point size and a string specifying\nthe font name. Otherwise, there is no font information.\n<\/p>\n<p>\nThat&#8217;s the end of the header section.  Next come\na series of dialog item templates, one for each control.\n<\/p>\n<p>\nEach item template begins the same way:\n<\/p>\n<pre>\nWORD  x;       \/\/ x-coordinate (DLUs)\nWORD  y;       \/\/ y-coordinate (DLUs)\nWORD  cx;      \/\/ width (DLUs)\nWORD  cy;      \/\/ height (DLUs)\nWORD  wID;     \/\/ control ID\nDWORD dwStyle; \/\/ window style\n<\/pre>\n<p>\nRecall that the dialog coordinates are recorded\nin dialog units (DLUs).\nFour x-DLUs and eight y-DLUs equals one &#8220;average&#8221; character.\n<\/p>\n<p>\nAfter the fixed start of the item template comes the class name,\neither as a null-terminated ANSI string or\n(and this is particularly weird)\nas single byte in the range 0x80 through 0xFF which encodes one\nof the &#8220;standard&#8221; window classes:\n<\/p>\n<ul>\n<li>0x80 = &#8220;button&#8221;\n<li>0x81 = &#8220;edit&#8221;\n<li>0x82 = &#8220;static&#8221;\n<li>0x83 = &#8220;listbox&#8221;\n<li>0x84 = &#8220;scrollbar&#8221;\n<li>0x85 = &#8220;combobox&#8221;\n<\/ul>\n<p>\n(Note that this encoding means that the first character of a\nwindow class name cannot be an extended character if you want\nto use it in a dialog template!)\n<\/p>\n<p>\nAfter the class name comes the control text, either as a null-terminated\nstring or as an ordinal.  If you use an ordinal, then the\nlpszName member of the CREATESTRUCT is a pointer to the three-byte\nordinal sequence (0xFF followed by the ordinal); otherwise it&#8217;s\na pointer to the string.  The only control I know of that knows\nwhat to do with the ordinal is the static control if you put it into\none of the image modes (SS_ICON or SS_BITMAP), in which\ncase the ordinal is a resource identifier for the image that the\nstatic displays.\n<\/p>\n<p>\nAfter the control text comes up to 256 bytes of &#8220;extra data&#8221;\nin the form of a byte count, followed by the actual data.\nIf there is no &#8220;extra data&#8221;, then use a byte count of zero.\n<\/p>\n<p>\nWhen the dialog manager creates a control, it passes a pointer\nto the &#8220;extra&#8221; data as the final LPVOID parameter to the\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/winui\/winui\/windowsuserinterface\/windowing\/windows\/windowreference\/windowfunctions\/createwindowex.asp\">\nCreateWindowEx<\/a> function.\n(As far as I can tell, there is no way to tell the resource\ncompiler to insert this extra data.  It&#8217;s one of those lurking\nfeatures that nobody has taken advantage of yet.)\n<\/p>\n<p>\nOkay, that&#8217;s all great and theoretical. But sometimes you just need\nto see it in front of you to understand it. So let&#8217;s take apart\nan actual 16-bit dialog resource.  I took this one from COMMCTRL.DLL;\nit&#8217;s the search\/replace dialog.\n<\/p>\n<pre>\n0000  C0 00 C8 80 0B 24 00 2C-00 E6 00 5E 00 00 00 52  .....$.,...^...R\n0010  65 70 6C 61 63 65 00 08-00 48 65 6C 76 00 04 00  eplace...Helv...\n0020  09 00 30 00 08 00 FF FF-00 00 00 50 82 46 69 26  ..0........P.Fi&amp;\n0030  6E 64 20 57 68 61 74 3A-00 00 36 00 07 00 72 00  nd What:..6...r.\n0040  0C 00 80 04 80 00 83 50-81 00 00 04 00 1A 00 30  .......P.......0\n0050  00 08 00 FF FF 00 00 00-50 82 52 65 26 70 6C 61  ........P.Re&amp;pla\n0060  63 65 20 57 69 74 68 3A-00 00 36 00 18 00 72 00  ce With:..6...r.\n0070  0C 00 81 04 80 00 83 50-81 00 00 05 00 2E 00 68  .......P.......h\n0080  00 0C 00 10 04 03 00 03-50 80 4D 61 74 63 68 20  ........P.Match\n0090  26 57 68 6F 6C 65 20 57-6F 72 64 20 4F 6E 6C 79  &amp;Whole Word Only\n00A0  00 00 05 00 3E 00 3B 00-0C 00 11 04 03 00 01 50  ....&gt;.;........P\n00B0  80 4D 61 74 63 68 20 26-43 61 73 65 00 00 AE 00  .Match &amp;Case....\n00C0  04 00 32 00 0E 00 01 00-01 00 03 50 80 26 46 69  ..2........P.&amp;Fi\n00D0  6E 64 20 4E 65 78 74 00-00 AE 00 15 00 32 00 0E  nd Next......2..\n00E0  00 00 04 00 00 03 50 80-26 52 65 70 6C 61 63 65  ......P.&amp;Replace\n00F0  00 00 AE 00 26 00 32 00-0E 00 01 04 00 00 03 50  ....&amp;.2........P\n0100  80 52 65 70 6C 61 63 65-20 26 41 6C 6C 00 00 AE  .Replace &amp;All...\n0110  00 37 00 32 00 0E 00 02-00 00 00 03 50 80 43 61  .7.2........P.Ca\n0120  6E 63 65 6C 00 00 AE 00-4B 00 32 00 0E 00 0E 04  ncel....K.2.....\n0130  00 00 03 50 80 26 48 65-6C 70 00 00              ...P.&amp;Help..\n<\/pre>\n<p>\nLet&#8217;s start with the header.<\/p>\n<pre>\n0000  C0 00 C8 80  \/\/ dwStyle\n0004  0B           \/\/ cItems\n0005  24 00 2C 00  \/\/ x, y\n0009  E6 00 5E 00  \/\/ cx, cy\n<\/pre>\n<p>\nIn other words, the header says\n<\/p>\n<table>\n<tr>\n<td>dwStyle<\/td>\n<td>= 0x80C800C0<\/td>\n<td>= WS_POPUP | WS_CAPTION | WS_SYSMENU |\n          DS_SETFONT | DS_MODALFRAME\n    <\/td>\n<\/tr>\n<tr>\n<td>cItems<\/td>\n<td>= 0x0B<\/td>\n<td>= 11<\/td>\n<\/tr>\n<tr>\n<td>x<\/td>\n<td>= 0x0024<\/td>\n<td>= 36<\/td>\n<\/tr>\n<tr>\n<td>y<\/td>\n<td>= 0x002C<\/td>\n<td>= 44<\/td>\n<\/tr>\n<tr>\n<td>cx<\/td>\n<td>= 0x00E6<\/td>\n<td>= 230<\/td>\n<\/tr>\n<tr>\n<td>cy<\/td>\n<td>= 0x005E<\/td>\n<td>= 94<\/td>\n<\/tr>\n<\/table>\n<p>\nAfter the header come the menu name, class name, and\ndialog title:\n<\/p>\n<pre>\n000D  00            \/\/ no menu\n000E  00            \/\/ default dialog class\n000F  52 65 70 6C 61 63 65 00 \/\/ \"Replace\"\n<\/pre>\n<p>\nNow, since the DS_SETFONT bit is set in the style,\nthe next section describes the font to be used by the dialog:\n<\/p>\n<pre>\n0017  08 00         \/\/ wSize = 8\n0019  48 65 6C 76 00 \/\/ \"Helv\"\n<\/pre>\n<p>\nAha, this dialog box uses 8pt Helv.\n<\/p>\n<p>\nNext come the eleven dialog item templates.\n<\/p>\n<pre>\n001E  04 00 09 00   \/\/ x, y\n0022  30 00 08 00   \/\/ cx, cy\n0026  FF FF         \/\/ wID\n0028  00 00 00 50   \/\/ dwStyle\n<\/pre>\n<p>\nSo this dialog item template says\n<\/p>\n<table>\n<tr>\n<td>x<\/td>\n<td>= 0x0004<\/td>\n<td>= 4<\/td>\n<\/tr>\n<tr>\n<td>y<\/td>\n<td>= 0x0009<\/td>\n<td>= 9<\/td>\n<\/tr>\n<tr>\n<td>cx<\/td>\n<td>= 0x0030<\/td>\n<td>= 48<\/td>\n<\/tr>\n<tr>\n<td>cy<\/td>\n<td>= 0x0008<\/td>\n<td>= 8<\/td>\n<\/tr>\n<tr>\n<td>wID<\/td>\n<td>= 0xFFFF<\/td>\n<td>= -1<\/td>\n<\/tr>\n<tr>\n<td>dwStyle<\/td>\n<td>= 0x50000000<\/td>\n<td>= WS_CHILD | WS_VISIBLE | SS_LEFT\n    <\/td>\n<\/tr>\n<\/table>\n<p>\nHow did I know that the style value 0x0000 should be interpreted\nas SS_LEFT and not, say, BS_PUSHBUTTON?  Because the window class\ntells me that what I have is a static control.\n<\/p>\n<pre>\n002C  82            \/\/ \"static\"\n<\/pre>\n<p>\nAfter the class name comes the control text.\n<\/p>\n<pre>\n002D  46 69 26 6E 64 20 57 68 61 74 3A 00 \/\/ \"Fi&amp;nd What:\"\n<\/pre>\n<p>\nAnd finally (for this dialog item template), we specify that we have\nno extra data:\n<\/p>\n<pre>\n0039  00            \/\/ no extra data\n<\/pre>\n<p>\nNow we repeat the above exercise for the other ten controls.\nI&#8217;ll just summarize here:\n<\/p>\n<pre>\n\/\/ Second control\n003A  36 00 07 00   \/\/ x, y\n003E  72 00 0C 00   \/\/ cx, cy\n0042  80 04         \/\/ wID\n0044  80 00 83 50   \/\/ dwStyle\n0048  81            \/\/ \"edit\"\n0049  00            \/\/ \"\"\n004A  00            \/\/ no extra data\n\/\/ Third control\n004B  04 00 1A 00   \/\/ x, y\n004F  30 00 08 00   \/\/ cx, cy\n0053  FF FF         \/\/ wID\n0055  00 00 00 50   \/\/ dwStyle\n0059  82            \/\/ \"static\"\n005A  52 65 26 70 6C 61 63 65 20 57 69 74 68 3A 00\n                    \/\/ \"Re&amp;place With:\"\n0069  00            \/\/ no extra data\n\/\/ Fourth control\n006A  36 00 18 00   \/\/ x, y\n006E  72 00 0C 00   \/\/ cx, cy\n0072  81 04         \/\/ wID\n0074  80 00 83 50   \/\/ dwStyle\n0078  81            \/\/ \"edit\"\n0079  00            \/\/ \"\"\n007A  00            \/\/ no extra data\n\/\/ Fifth control\n007B  05 00 2E 00   \/\/ x, y\n007F  68 00 0C 00   \/\/ cx, cy\n0083  10 04         \/\/ wID\n0085  03 00 03 50   \/\/ dwStyle\n0089  80            \/\/ \"button\"\n008A  4D 61 74 63 68 20 26 57 68 6F 6C 65 20 57\n      6F 72 64 20 4F 6E 6C 79 00\n                    \/\/ \"Match &amp;Whole Word Only\"\n00A1  00            \/\/ no extra data\n\/\/ Sixth control\n00A2  05 00 3E 00   \/\/ x, y\n00A6  3B 00 0C 00   \/\/ cx, cy\n00AA  11 04         \/\/ wID\n00AC  03 00 01 50   \/\/ dwStyle\n00B0  80            \/\/ \"button\"\n00B1  4D 61 74 63 68 20 26 43 61 73 65 00\n                    \/\/ \"Match &amp;Case\"\n00BD  00            \/\/ no extra data\n\/\/ Seventh control\n00BE  AE 00 04 00   \/\/ x, y\n00C2  32 00 0E 00   \/\/ cx, cy\n00C6  01 00         \/\/ wID\n00C8  01 00 03 50   \/\/ dwStyle\n00CC  80            \/\/ \"button\"\n00CD  26 46 69 6E 64 20 4E 65 78 74 00\n                    \/\/ \"&amp;Find Next\"\n00D8  00            \/\/ no extra data\n\/\/ Eighth control\n00D9  AE 00 15 00   \/\/ x, y\n00DD  32 00 0E 00   \/\/ cx, cy\n00E1  00 04         \/\/ wID\n00E3  00 00 03 50   \/\/ dwStyle\n00E7  80            \/\/ \"button\"\n00E8  26 52 65 70 6C 61 63 65 00\n                    \/\/ \"&amp;Replace\"\n00F1  00            \/\/ no extra data\n\/\/ Ninth control\n00F2  AE 00 26 00   \/\/ x, y\n00F6  32 00 0E 00   \/\/ cx, cy\n00FA  01 04         \/\/ wID\n00FC  00 00 03 50   \/\/ dwStyle\n0100  80            \/\/ \"button\"\n0101  52 65 70 6C 61 63 65 20 26 41 6C 6C 00\n                    \/\/ \"Replace &amp;All\"\n010E  00            \/\/ no extra data\n\/\/ Tenth control\n010F  AE 00 37 00   \/\/ x, y\n0113  32 00 0E 00   \/\/ cx, cy\n0117  02 00         \/\/ wID\n0119  00 00 03 50   \/\/ dwStyle\n011D  80            \/\/ \"button\"\n011E  43 61 6E 63 65 6C 00\n                    \/\/ \"Cancel\"\n0125  00            \/\/ no extra data\n\/\/ Eleventh control\n0126  AE 00 4B 00   \/\/ x, y\n012A  32 00 0E 00   \/\/ cx, cy\n012E  0E 04         \/\/ wID\n0130  00 00 03 50   \/\/ dwStyle\n0134  80            \/\/ \"button\"\n0135  26 48 65 6C 70 00\n                    \/\/ \"&amp;Help\"\n013B  00            \/\/ no extra data\n<\/pre>\n<p>\nAnd that&#8217;s the dialog template.  We can now reconstruct the\nresource compiler source code from this template:\n<\/p>\n<pre>\nDIALOG 36, 44, 230, 94\nSTYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | NOT WS_VISIBLE\nCAPTION \"Replace\"\nFONT 8, \"Helv\"\nBEGIN\n    CONTROL \"Fi&amp;nd What:\", -1, \"static\", SS_LEFT,\n            4, 9, 48, 8\n    CONTROL \"\", 0x0480, \"edit\",\n            WS_BORDER | WS_GROUP | WS_TABSTOP | ES_AUTOHSCROLL,\n            54, 7, 114, 12\n    CONTROL \"Re&amp;place With:\", -1, \"static\", SS_LEFT,\n            4, 26, 48, 8\n    CONTROL \"\", 0x0481, \"edit\",\n            WS_BORDER | WS_GROUP | WS_TABSTOP | ES_AUTOHSCROLL,\n            54, 24, 114, 12\n    CONTROL \"Match &amp;Whole Word Only\", 0x0410, \"button\",\n            WS_GROUP | WS_TABSTOP | BS_AUTOCHECKBOX,\n            5, 46, 104, 12\n    CONTROL \"Match &amp;Case\", 0x0411, \"button\",\n            WS_TABSTOP | BS_AUTOCHECKBOX,\n            5, 62, 59, 12\n    CONTROL \"&amp;Find Next\", IDOK, \"button\",\n            WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON,\n            174, 4, 50, 14\n    CONTROL \"&amp;Replace\", 0x0400, \"button\",\n            WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON,\n            174, 21, 50, 14\n    CONTROL \"Replace &amp;All\", 0x0401, \"button\",\n            WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON,\n            174, 38, 50, 14\n    CONTROL \"Cancel\", IDCANCEL, \"button\",\n            WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON,\n            174, 55, 50, 14\n    CONTROL \"Cancel\", 0x040E, \"button\",\n            WS_GROUP | WS_TABSTOP | BS_PUSHBUTTON,\n            174, 75, 50, 14\nEND\n<\/pre>\n<p>\nNotice that we didn&#8217;t explicitly say &#8220;DS_SETFONT&#8221; in the dialog&#8217;s\nSTYLE directive since that is implied by the &#8220;FONT&#8221; directive.\nAnd since WS_VISIBLE is on by default, we didn&#8217;t have to say it;\nrather we had to explicitly refute it in the places it wasn&#8217;t wanted.\n<\/p>\n<p>\nNow if you take a look in your SDK header files, you&#8217;ll find\ndlgs.h and findtext.dlg which pretty much match up with the\ntemplate above, giving names to the magic values like 0x0400\nand positioning the controls in the same place as above.\nYou&#8217;ll find some minor differences, though, since the header\nfiles in the SDK are for the 32-bit Find\/Replace dialog and\nthe one above is the 16-bit Find\/Replace dialog, but you&#8217;ll see\nthat it still matches up pretty well.\n<\/p>\n<p>\nNext time:\n<a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/06\/21\/161375.aspx\">\nThe 32-bit DIALOG template<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the history of Windows, there have been four versions of dialog templates. And despite the changes, you&#8217;ll see that they&#8217;re basically all the same. First, there was the classic Windows 1.0 dialog template. It starts like this: DWORD dwStyle; \/\/ dialog style BYTE cItems; \/\/ number of controls in this dialog WORD x; \/\/ [&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-38803","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>In the history of Windows, there have been four versions of dialog templates. And despite the changes, you&#8217;ll see that they&#8217;re basically all the same. First, there was the classic Windows 1.0 dialog template. It starts like this: DWORD dwStyle; \/\/ dialog style BYTE cItems; \/\/ number of controls in this dialog WORD x; \/\/ [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38803","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=38803"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/38803\/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=38803"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=38803"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=38803"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}