Date: | June 21, 2004 / year-entry #245 |
Tags: | history |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20040621-00/?p=38793 |
Comments: | 21 |
Summary: | Okay, last time we talked about the 16-bit classic DIALOG template. This time, we're going to talk about the 32-bit classic DIALOG template. There really isn't much going on. Some 8-bit fields got expanded to 16-bit fields, some 16-bit fields got expanded to 32-bit fields, extended styles were added, and all strings got changed from... |
Okay, last time we talked about the 16-bit classic DIALOG template. This time, we're going to talk about the 32-bit classic DIALOG template. There really isn't much going on. Some 8-bit fields got expanded to 16-bit fields, some 16-bit fields got expanded to 32-bit fields, extended styles were added, and all strings got changed from ANSI to Unicode. The template starts like this: DWORD dwStyle; // dialog style DWORD dwExStyle; // extended dialog style WORD cItems; // number of controls in this dialog WORD x; // x-coordinate WORD y; // y-coordinate WORD cx; // width WORD cy; // height
This is basically the same as the 16-bit dialog template,
except that there's a new After this header come a series of strings, just like in 16-bit dialog templates. But this time, the strings are Unicode. For example, if you wanted to store the string "Hello", you would write out the twelve bytes 48 00 65 00 6C 00 6C 00 6F 00 00 00 ; "Hello" As with the 16-bit case, in the 32-bit dialog template, you can often specify an ordinal instead of a string. Here, it's done by writing the bytes FF 00 followed by the 16-bit ordinal (in little-endian format). For example, if you wanted to specify the ordinal 42, you would write out the four bytes FF 00 2A 00 ; 00FF followed by WORD (little-endian) The three strings are the same as last time:
If the DS_SETFONT style is set, then what follows next is a WORD indicating the point size and a string specifying the font name. Otherwise, there is no font information. Same as in the 16-bit dialog template. So far, everything has been WORD-aligned. After the header comes a series of dialog item templates. Each item template begins on a DWORD boundary. (Insert padding if necessary to achieve this.) DWORD dwStyle; // window style DWORD dwExStyle; // window extended style WORD x; // x-coordinate (DLUs) WORD y; // y-coordinate (DLUs) WORD cx; // width (DLUs) WORD cy; // height (DLUs) WORD wID; // control ID As before, the dialog coordinates are recorded in dialog units (DLUs). Next comes the class name, either as a null-terminated Unicode string or as an ordinal. The ordinal codes for the six "standard" window classes are the same as for 16-bit dialog templates:
After the class name comes the control text, either as a null-terminated string or as an ordinal, following the same rules as for the 16-bit template. Extra weirdness: To specify an ordinal here, use FFFF instead of 00FF as the ordinal marker. I don't know why. After the control text comes up to 65535 bytes of "extra data" in the form of a 16-bit count, followed by the actual data. If there is no "extra data", then use a count of zero. And that's all there is. As with last time, I'll present an annotated dialog template. 0000 C4 20 C8 80 00 00 00 00-0B 00 24 00 2C 00 E6 00 . ........$.,... 0010 5E 00 00 00 00 00 52 00-65 00 70 00 6C 00 61 00 ^.....R.e.p.l.a. 0020 63 00 65 00 00 00 08 00-4D 00 53 00 20 00 53 00 c.e.....M.S. .S. 0030 68 00 65 00 6C 00 6C 00-20 00 44 00 6C 00 67 00 h.e.l.l. .D.l.g. 0040 00 00 00 00 00 00 02 50-00 00 00 00 04 00 09 00 .......P........ 0050 30 00 08 00 FF FF FF FF-82 00 46 00 69 00 26 00 0.........F.i.&. 0060 6E 00 64 00 20 00 77 00-68 00 61 00 74 00 3A 00 n.d. .w.h.a.t.:. 0070 00 00 00 00 80 00 83 50-00 00 00 00 36 00 07 00 .......P....6... 0080 72 00 0C 00 80 04 FF FF-81 00 00 00 00 00 00 00 r............... 0090 00 00 02 50 00 00 00 00-04 00 1A 00 30 00 08 00 ...P........0... 00A0 FF FF FF FF 82 00 52 00-65 00 26 00 70 00 6C 00 ......R.e.&.p.l. 00B0 61 00 63 00 65 00 20 00-77 00 69 00 74 00 68 00 a.c.e. .w.i.t.h. 00C0 3A 00 00 00 00 00 00 00-80 00 83 50 00 00 00 00 :..........P.... 00D0 36 00 18 00 72 00 0C 00-81 04 FF FF 81 00 00 00 6...r........... 00E0 00 00 00 00 03 00 03 50-00 00 00 00 05 00 2E 00 .......P........ 00F0 68 00 0C 00 10 04 FF FF-80 00 4D 00 61 00 74 00 h.........M.a.t. 0100 63 00 68 00 20 00 26 00-77 00 68 00 6F 00 6C 00 c.h. .&.w.h.o.l. 0110 65 00 20 00 77 00 6F 00-72 00 64 00 20 00 6F 00 e. .w.o.r.d. .o. 0120 6E 00 6C 00 79 00 00 00-00 00 00 00 03 00 01 50 n.l.y..........P 0130 00 00 00 00 05 00 3E 00-3B 00 0C 00 11 04 FF FF ......>.;....... 0140 80 00 4D 00 61 00 74 00-63 00 68 00 20 00 26 00 ..M.a.t.c.h. .&. 0150 63 00 61 00 73 00 65 00-00 00 00 00 01 00 03 50 c.a.s.e........P 0160 00 00 00 00 AE 00 04 00-32 00 0E 00 01 00 FF FF ........2....... 0170 80 00 26 00 46 00 69 00-6E 00 64 00 20 00 4E 00 ..&.F.i.n.d. .N. 0180 65 00 78 00 74 00 00 00-00 00 00 00 00 00 01 50 e.x.t..........P 0190 00 00 00 00 AE 00 15 00-32 00 0E 00 00 04 FF FF ........2....... 01A0 80 00 26 00 52 00 65 00-70 00 6C 00 61 00 63 00 ..&.R.e.p.l.a.c. 01B0 65 00 00 00 00 00 00 00-00 00 01 50 00 00 00 00 e..........P.... 01C0 AE 00 26 00 32 00 0E 00-01 04 FF FF 80 00 52 00 ..&.2.........R. 01D0 65 00 70 00 6C 00 61 00-63 00 65 00 20 00 26 00 e.p.l.a.c.e. .&. 01E0 41 00 6C 00 6C 00 00 00-00 00 00 00 00 00 01 50 A.l.l..........P 01F0 00 00 00 00 AE 00 37 00-32 00 0E 00 02 00 FF FF ......7.2....... 0200 80 00 43 00 61 00 6E 00-63 00 65 00 6C 00 00 00 ..C.a.n.c.e.l... 0210 00 00 00 00 00 00 01 50-00 00 00 00 AE 00 4B 00 .......P......K. 0220 32 00 0E 00 0E 04 FF FF-80 00 26 00 48 00 65 00 2.........&.H.e. 0230 6C 00 70 00 00 00 00 00 l.p..... As before, we start with the header. 0000 C4 20 C8 80 // dwStyle 0004 00 00 00 00 // dwExStyle 0008 0B 00 // cItems 000A 24 00 2C 00 // x, y 000E E6 00 5E 00 // cx, cy In other words, the header says
After the header come the menu name, class name, and dialog title: 0012 00 00 // no menu 0014 00 00 // default dialog class 0016 52 00 65 00 70 00 6C 00 61 00 63 00 65 00 00 00 // "Replace" Again, since the DS_SETFONT bit is set in the style, the next section describes the font to be used by the dialog: 0026 08 00 // wSize = 8 0028 4D 00 53 00 20 00 53 00 68 00 65 00 6C 00 6C 00 20 00 44 00 6C 00 67 00 00 00 // "MS Shell Dlg" This dialog box uses 8pt "MS Shell Dlg" as its dialog font. Next come the eleven dialog item templates. Not remember that each template must be DWORD-aligned, so we need some padding here to get up to a four-byte boundary. 0042 00 00 // Padding for alignment Now that we are once again DWORD-aligned, we can read the first dialog item template. 0044 00 00 02 50 // dwStyle 0048 00 00 00 00 // dwExStyle 004C 04 00 09 00 // x, y 0050 30 00 08 00 // cx, cy 0054 FF FF // wID 0056 FF FF 82 00 // "static" 005A 46 00 69 00 26 00 0060 6E 00 64 00 20 00 77 00-68 00 61 00 74 00 3A 00 0070 00 00 // "Fi&nd what:" 0072 00 00 // no extra data Notice here that the "static" class was encoded as an ordinal. The template for this item is therefore
The other controls are similarly unexciting. // Second control 0074 80 00 83 50 // dwStyle 0078 00 00 00 00 // dwExStyle 007C 36 00 07 00 // x, y 0080 72 00 0C 00 // cx, cy 0084 80 04 // wID 0086 FF FF 81 00 // "edit" 008A 00 00 // "" 008C 00 00 // no extra data 008E 00 00 // padding to achieve DWORD alignment // Third control 0090 00 00 02 50 // dwStyle 0094 00 00 00 00 // dwExStyle 0098 04 00 1A 00 // x, y 009C 30 00 08 00 // cx, cy 00A0 FF FF // wID 00A2 FF FF 82 00 // "static" 00A6 52 00 65 00 26 00 70 00 6C 00 00B0 61 00 63 00 65 00 20 00 77 00 69 00 74 00 68 00 00C0 3A 00 00 00 // "Re&place with:" 00C4 00 00 // no extra data 00C6 00 00 // padding to achieve DWORD alignment // Fourth control 00C8 80 00 83 50 // dwStyle 00CC 00 00 00 00 // dwExStyle 00D0 36 00 18 00 // x, y 00D4 72 00 0C 00 // cx, cy 00D8 81 04 // wID 00DA FF FF 81 00 // "edit" 00DE 00 00 // "" 00E0 00 00 // no extra data 00E2 00 00 // padding to achieve DWORD alignment // Fifth control 00E4 03 00 03 50 // dwStyle 00E8 00 00 00 00 // dwExStyle 00EC 05 00 2E 00 // x, y 00F0 68 00 0C 00 // cx, cy 00F4 10 04 // wID 00F6 FF FF 80 00 // "button" 00FA 4D 00 61 00 74 00 0100 63 00 68 00 20 00 26 00 77 00 68 00 6F 00 6C 00 0110 65 00 20 00 77 00 6F 00 72 00 64 00 20 00 6F 00 0120 6E 00 6C 00 79 00 00 00 // "Match &whole word only" 0128 00 00 // no extra data 012A 00 00 // padding to achieve DWORD alignment // Sixth control 012C 03 00 01 50 // dwStyle 0130 00 00 00 00 // dwExStyle 0134 05 00 3E 00 // x, y 0138 3B 00 0C 00 // cx, cy 013C 11 04 // wID 013E FF FF 80 00 // "button" 0142 4D 00 61 00 74 00 63 00 68 00 20 00 26 00 0150 63 00 61 00 73 00 65 00 00 00 // "Match &case" 015A 00 00 // no extra data // Seventh control 015C 01 00 03 50 // dwStyle 0160 00 00 00 00 // dwExStyle 0164 AE 00 04 00 // x, y 0168 32 00 0E 00 // cx, cy 016C 01 00 // wID 016E FF FF 80 00 // "button" 0172 26 00 46 00 69 00 6E 00 64 00 20 00 4E 00 0180 65 00 78 00 74 00 00 00 // "&Find Next" 0188 00 00 // no extra data 018A 00 00 // padding to achieve DWORD alignment // Eighth control 018C 00 00 01 50 // dwStyle 0190 00 00 00 00 // dwExStyle 0194 AE 00 15 00 // x, y 0198 32 00 0E 00 // cx, cy 019C 00 04 // wID 019E FF FF 80 00 // "button" 01A2 26 00 52 00 65 00-70 00 6C 00 61 00 63 00 01B0 65 00 00 00 // "&Replace" 01B4 00 00 // no extra data 01B6 00 00 // padding to achieve DWORD alignment // Ninth control 01B8 00 00 01 50 // dwStyle 01BC 00 00 00 00 // dwExStyle 01C0 AE 00 26 00 // x, y 01C4 32 00 0E 00 // cx, cy 01C8 01 04 // wID 01CA FF FF 80 00 // "button" 01CE 52 00 01D0 65 00 70 00 6C 00 61 00 63 00 65 00 20 00 26 00 01E0 41 00 6C 00 6C 00 00 00 // "Replace &All" 01E8 00 00 // no extra data 01EA 00 00 // padding to achieve DWORD alignment // Tenth control 01EC 00 00 01 50 // dwStyle 01F0 00 00 00 00 // dwExStyle 01F4 AE 00 37 00 // x, y 01F8 32 00 0E 00 // cx, cy 01FC 02 00 // wID 01FE FF FF 80 00 // "button" 0202 43 00 61 00 6E 00 63 00 65 00 6C 00 00 00 // "Cancel" 0210 00 00 // no extra data 0212 00 00 // padding to achieve DWORD alignment // Eleventh control 0214 00 00 01 50 // dwStyle 0218 00 00 00 00 // dwExStyle 021C AE 00 4B 00 // x, y 0220 32 00 0E 00 // cx, cy 0224 0E 04 // wID 0226 FF FF 80 00 // "button" 022A 26 00 48 00 65 00 6C 00 70 00 00 00 // "&Help" 0236 00 00 // no extra data Whew. Tedious and entirely unexciting. Here's the original resource compiler source code that we reverse-engineered: DIALOG 36, 44, 230, 94 STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_3DLOOK | NOT WS_VISIBLE CAPTION "Replace" FONT 8, "MS Shell Dlg" BEGIN CONTROL "Fi&nd What:", -1, "static", WS_GROUP | SS_LEFT, 4, 9, 48, 8 CONTROL "", 0x0480, "edit", WS_BORDER | WS_GROUP | WS_TABSTOP | ES_AUTOHSCROLL, 54, 7, 114, 12 CONTROL "Re&place with:", -1, "static", WS_GROUP | SS_LEFT, 4, 26, 48, 8 CONTROL "", 0x0481, "edit", WS_BORDER | WS_GROUP | WS_TABSTOP | ES_AUTOHSCROLL, 54, 24, 114, 12 CONTROL "Match &whole word only", 0x0410, "button", WS_GROUP | WS_TABSTOP | BS_AUTOCHECKBOX, 5, 46, 104, 12 CONTROL "Match &case", 0x0411, "button", WS_TABSTOP | BS_AUTOCHECKBOX, 5, 62, 59, 12 CONTROL "&Find Next", IDOK, "button", WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON, 174, 4, 50, 14 CONTROL "&Replace", 0x0400, "button", WS_TABSTOP | BS_PUSHBUTTON, 174, 21, 50, 14 CONTROL "Replace &All", 0x0401, "button", WS_TABSTOP | BS_PUSHBUTTON, 174, 38, 50, 14 CONTROL "Cancel", IDCANCEL, "button", WS_TABSTOP | BS_PUSHBUTTON, 174, 55, 50, 14 CONTROL "Cancel", 0x040E, "button", WS_TABSTOP | BS_PUSHBUTTON, 174, 75, 50, 14 END As before, we didn't explicitly say "DS_SETFONT" in the dialog's STYLE directive since that is implied by the "FONT" directive, and we took advantage of the fact that WS_VISIBLE is on by default. And you probably recognize this dialog from yesterday. It's the replace dialog from findtext.dlg. (Though it's not exactly the same since the findtext.dlg template uses some shorthand directives like DEFPUSHBUTTON instead of manually writing out the details of the button control as a CONTROL.) Next time: The 16-bit extended dialog template, also known as DIALOGEX. |
Comments (21)
Comments are closed. |
What’s the reason to pad fields in structures like this to DWORD boundaries? This is always a lot more work to program for — and test the special cases that require padding. It’s especially irritating with DIB scan lines.
The only reason I can think of is that it is marginally faster. Sounds like a good example of premature optimization, or am I mistaken?
It’s not an optimization. It’s a necessity.
The overwhelming dominance of the x86 architecture in the world of Win32 makes people think that the way the x86 does things is normal, when in reality the x86 is the weirdo.
PPC, MIPS, Alpha AXP, ia64 all crash if you access unaligned data. x86 is the weirdo: It permits unaligned data access.
It could be a remnant of the Alpha/MIPS NT effort – accessing unaligned data caused a segfault instead of simply being slow. Alternate theory: the structs used to hold this data are compiled with dword alignment and loaded directly from a file, so unaligned data is misinterpreted.
I don’t understand why you would even want to have unaligned data access. In my opinion it only makes things more complicated.
Can anyone point to a case where it is better/cleaner than using aligned?
If space is really tight, as it was way back when, then every byte counts. Otherwise, go right a head and align your data – I do.
It makes your code cleaner if you don’t have to worry about unaligned stuff. For the most part this is transparent to you but there are some areas where it isn’t. You pay for unaligned memory access in higher cycle counts, not having atomic operations, and segfaults in non x86 processors. Win64 supports bad code with SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT) or the __unaligned qualifier (how thoughtful of them).
JamKnight:
Unaligned is better than aligned when you’re dealing with different CPUs that have different alignment requirements from the get go.
(eg. a CPU that required 16bit alignment vs. one that requires 64bit alignment… but you design everything before the 64bit one is on the horizon).
But yeah, it’s a real edge case.
Unfortunatly, one cannot use control’s text ordinal to display text – it works for icon and bitmaps only. pity
Raymond: the x, y, cx, cy fields should be signed and there is no 0xFF 0x00 to specify ordinals, it’s all 0xFFFF.
You write "strings got changed from ANSI to Unicode": what kind of encoding is used for Unicode? Is it UCS-2 or UTF-16?
I never have been able to find the answer on this…
Holger: What’s the difference between UCS-2 and UTF-16? As far as I can tell they both use surrogate pairs.
@Raymond: no, UCS-2 cannot use surrogate pairs and is limit to codepoints up tp $FFFF. AFAIK that was the reason why UTF-16 was created in the first place.
I have no idea. But instead of just saying "Gosh I will never know", I decided to search on google for "site:msdn.microsoft.com surrogate pairs" and it found this page
http://msdn.microsoft.com/library/en-us/intl/unicode_192r.asp . Please, people, don’t be lazy. Do some searching yourself before asking questions. I have better things to do with my time.
I’m sorry to have wasted your time, Raymond, but I really did search earlier for an answer to this. It just never occured to me to search for "surrogate pairs".
But finally, thanks to you, I have an answer: starting with W2K UTF-16 (and therefore surrogate pairs) are supported, up until then it was UCS-2.
Many thanks for your help!
For example, with 24-bit DIBs it is a pain in the behind because you can’t write
lpPixel = lpData + 3 * (x + y * width);
but the tedious:
byteWidth = (width * 3 + 3) & 0xFFFFFFFC;
lpPixel = lpData + 3 * x + y * byteWidth;
Marcdlg: Support for misaligned access is an optional feature of the PowerPC architecture, at least in little-endian mode (which is what Windows uses). The early PowerPCs (601, 603, 604) raise an exception for it.
asdf: 0xFF 0xFF and 0xFF 0x00 are both valid and mean different things! I was not sufficient clear.
0xFF 0xFF means "What comes next is a special class ordinal (0x80 = button, etc.)".
0xFF 0x00 means "What comes next is a class ordinal (atom)."
Trying to capture the changes in a table.