December, 2006

  • The Old New Thing

    2006 end-of-year link clearance

    • 24 Comments

    A few random links that I've collected.

    And then the obligatory plug for my column in TechNet Magazine:

    And then the obligatory book plug: The electronic-only PDF version is now available for purchase, and it's cheaper than the dead tree edition. (Don't forget that the dead tree edition comes with 45 days of free access to the electronic edition.)

    My prediction? "Jim Allchin will retire on November 13, 2006." I was wrong. I based my prediction on the fact that Microsoft announced that Allchin "plans to retire at the end of calendar year 2006 following the commercial availability of Windows Vista." The year was set; the rest was trying to guess the day. I haven't seen any announcement saying that plans have changed, so I assume it's still operative. The year isn't over yet, but there's not much time left.

    (Then again, what is commercial availability? Apparently, the PR people think it means "the date the product is available to the general public at retail," but to me it means "the date the product can be purchased." So-called business availability was last month, and selling stuff to businesses is commerce, so that counts as commercial availability in my book. But apparently my interpretation of the English language doesn't count for anything, so I'm expecting to see Jim's letter of resignation on January 31st.)

  • The Old New Thing

    Stop the madness: Subdirectories of My Documents

    • 118 Comments

    As a follow-up to the difference between My Documents and Application Data, I'd like to rant about all the subdirectories of My Documents that programs create because they think they're so cool.

    • Visual Studio Projects
    • My eBooks
    • My Received Files
    • Remote Desktops
    • My Scans
    • My Data Sources
    • My Virtual Machines
    • My Archives

    I'm sure there are more.

    Everything in the My Documents folder the user should be able to point to and say, "I remember creating that file on such-and-such date when I did a 'Save' from Program Q." If it doesn't pass that test, then don't put it into My Documents. Use Application Data.

    And don't create subdirectories off of My Documents. If the user wants to organize their documents into subdirectories, that's their business. You just ask them where they want their documents and let it go at that.

    (Yes, I'm not a fan of My Music, My Videos, and My Pictures, either.)

    Omar Shahine points out that Apple has similar guidelines for the Macintosh. I wonder how well people follow them.

  • The Old New Thing

    Linda Hunt's advice for Oscar-winners

    • 3 Comments

    Academy-award winning actress Linda Hunt reminds newer Oscar-winners, "It's not about you."

  • The Old New Thing

    The social skills of a thermonuclear device, part 3

    • 34 Comments

    Some years ago, a group different from the one I worked in invited me to "volunteer" to help them with serious problems they were having with their product. They asked to "borrow" me for one week so that I could magically resolve all their issues. I wasn't really that familiar with their product, and I certainly didn't know how it worked internally, so I didn't think I could actually be much help given just one week. But they kept insisting that I "volunteer" to help them, until I finally wrote,

    I have a lot of vacation days and I'm not afraid to use them.

    That one line catapulted me into thermonuclear device territory.

  • The Old New Thing

    I can't believe they actually can't think of a name for the recent storm

    • 10 Comments

    The Seattle Times reports that the National Weather Service is inviting suggestions from the public on what to call the recent windstorm. They're baffled because "the storm didn't fall on a holiday."

    Huh?

    The storm blew in on the evening of the 14th, but its effects weren't really felt until the morning of the 15th, and the first dark night for everyone was... the first night of Hanukkah, the Festival of Lights. Everybody in the Seattle area was lighting candles and celebrating Hanukkah (mostly unwittingly).

    Gosh, I wonder what we should call this storm? If you have any ideas, send your suggestion to namethewindstorm@noaa.gov.

    (By the way, in case you missed it, here's the picture of the house that had ten trees fall on it.)

  • The Old New Thing

    The first parameter to VerQueryValue really must be a buffer you obtained from GetFileVersionInfo

    • 3 Comments

    The documentation for the VerQueryValue function states that the first parameter is a "pointer to the buffer containing the version-information resource returned by the GetFileVersionInfo function." Some people, however, decide to bypass this step and pass a pointer to data that was obtained some other way, and then wonder why VerQueryValue doesn't work.

    The documentation says that the first parameter to VerQueryValue must be a buffer returned by the GetFileVersionInfo function for a reason. The buffer returned by GetFileVersionInfo is an opaque data block specifically formatted so that VerQueryValue will work. You're not supposed to look inside that buffer, and you certainly can't try to "obtain the data some other way". Because if you do, VerQueryValue will look for something in a buffer that is not formatted in the manner the function expects.

    (And it can't even detect that the buffer is improperly formatted because there is no cbSize parameter to the VerQueryValue function that tells it how big the buffer is. Without that information, VerQueryValue can't check that, say, all the internal values are in range, since it doesn't know what "out-of-range" is! Is a value of 4000 out of range? It would be if the buffer were only 3000 bytes long. But it would be okay if the buffer were 5000 bytes long. Since there is no size parameter, the the VerQueryValue function is forced to assume that everything is okay.)

    If it wasn't obvious enough from the documentation that you can't just pass a pointer to a version resource obtained "some other way", it's even more obvious once you see the format of 32-bit version resources. Notice that all strings are stored in Unicode. But if you call the ANSI version VerQueryValueA to request a string, the function has to give you a pointer to an ANSI string. There is no ANSI version of the string in the raw version resource, so what can it possibly return? You can't return a pointer to something that doesn't exist. VerQueryValueA needs to produce an ANSI string, and it does so from memory that GetFileVersionInfo prepared when the resources were extracted.

    That there is no cbSize parameter to VerQueryValue was a failure of the original design of the function, but a slightly more understandable one when you look at the original design of 16-bit version resources: Since 16-bit Windows didn't have Unicode support, there was only one version of VerQueryValue, and it operated on ANSI strings. The 16-bit version resource format used ANSI strings, so VerQueryValue could just return a pointer into the raw version resource. No character set conversion was necessary, and therefore no need to reserve additional space as a string conversion buffer, no need for GetFileVersionInfo to "prepare" a buffer so that VerQueryValue could convert from one character set to another.

  • The Old New Thing

    The Old New Thing book will also be available electronically

    • 13 Comments

    We interrupt this religious holiday for an important commercial announcement. As a special Christmas present, my new best friends at Addison-Wesley sent me an advance copy of the dead-tree edition of my book. (Obligatory plug: Order it from Amazon. You know I want you to.)

    One commenter asked whether my book would be available electronically. On the copyright page of the book (that's the back side of the title page) there is a section titled This Book Is Safari Enabled. You can follow the instructions there to gain access to the online edition of the book for 45 days. I'm told that the electronic edition of the book will also be available in multiple formats including PDF and something called eMobipocket, whatever that is. (The ISBN for the electronic edition is 0321491955.)

  • The Old New Thing

    The evolution of version resources - corrupted 32-bit version resources

    • 11 Comments

    Last time we looked at the format of 32-bit version resources, but I ended with the remark that what you saw purported to be the resources of shell32.dll but actually weren't. What's going on here?

    The resources I presented last time were what the resources of shell32.dll should have been, but in fact they aren't.

    A common mistake in generating 32-bit resources is to mistreat the cbData field of the structure I called a VERSIONNODE as a count of characters rather than a count of bytes if the type is Unicode text. Even Microsoft's own Resource Compiler has fallen into this trap! For example, consider this VERSIONNODE I presented last time:

    0098  4C 00         // cbNode (node ends at 0x0088 + 0x004C = 0x00D40)
    009A  2C 00         // cbData
    009C  01 00         // wType = 1 (string data)
    009E  43 00 6F 00 6D 00 70 00 61 00 6E 00 79 00 4E 00
          61 00 6D 00 65 00 00 00
                        // L"CompanyName" + null terminator
    00B6  00 00         // padding to restore alignment
    00B8  4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00
          74 00 20 00 43 00 6F 00 72 00 70 00 6F 00 72 00
          61 00 74 00 69 00 6F 00 6E 00 00 00
                        // L"Microsoft Corporation" + null terminator
    00E4                // no padding needed
    

    In real life, the data take the following form:

    0098  4C 00         // cbNode (node ends at 0x0088 + 0x004C = 0x00D40)
    009A  16 00         // cchData (!)
    009C  01 00         // wType = 1 (string data)
    ...
    

    These malformed version resources manage to get away without crashing too horribly because the standard format of version resources uses string data only in leaf nodes. Therefore, the incorrect cbData affects only the node itself and doesn't cause the child nodes to be parsed incorrectly (since there are no child nodes).

    Until somebody tries to read, say, \StringFileInfo\040904B0\CompanyName\oops. After the VerQueryValue function locates the VERSIONNODE corresponding to CompanyName, it tries to locate the first child node and, due to the incorrect cbData, ends up misinterpreting the middle of the string as if it were the start of a child VERSIONNODE. Things only go downhill from there.

    They're just lucky that nobody actually asks for that.

    But wait, there's more. Somebody who calls the VerQueryValueA function expects to have the version string returned as ANSI, so VerQueryValueA needs to know how many characters to convert from Unicode to ANSI. If VerQueryValue trusted the erroneous cbData value, then ANSI callers would get only half the data they were expecting.

    As a result of this mess, the VerQueryValue function keeps its eyes open and anticipates that the version resource it was given to parse may have been generated by one of these buggy version resource compilers and goes to some extra effort to accommodate those bugs.

  • The Old New Thing

    The unanswered Explainer questions

    • 12 Comments

    Slate's Explainer column answers questions about current events. Sometimes they do it multiple times, as they did when I asked them how to pronounce the name Pinochet and they said Pee-no-CHAY, then later corrected themselves with pin-oh-CHET, and then again re-corrected themselves with Yes.

    Yesterday, the Explainer provided a selection of the questions they received and didn't answer and invited the readers to vote on which one they would like to see answered. My favorite question was the one that begins "I have a sister that stresses the hell out of me," and goes on and on about the car accident, how her sister complains and complains, how she had to tell the sister to stop bugging her with her problems, I mean, I was in a car accident, and concludes, "I really need to know if a person can really stress you out with the same old thing over and over and over again. PLEASE ANSWER BACK ASAP." Comedy gold. If you made this stuff up people would say it was too unrealistic.

    As for which one I would actually like answered, I don't know. They're all so goofy, and the answer wouldn't be all that enlightening.

  • The Old New Thing

    The evolution of version resources - 32-bit version resources

    • 6 Comments

    Last time we looked at the format of 16-bit version resources. The 32-bit version is nearly identical, except that everything is now in Unicode. Each node is stored in the following structure (in pseudo-C):

    struct VERSIONNODE {
      WORD  cbNode;
      WORD  cbData;
      WORD  wType;
      WCHAR wszName[];
      BYTE  rgbPadding1[]; // DWORD alignment
      union {
       BYTE  rgbData[cbData];
       WCHAR wszValue[cbData / sizeof(WCHAR)];
      };
      BYTE  rgbPadding2[]; // DWORD alignment
      VERSIONNODE rgvnChildren[];
    };
    

    In words, each version node begins with a 16-bit value describing the size of the nodes in bytes (including its children), followed by a 16-bit value that specifies how much data (either binary or text) are associated with the node. The wType is zero if the node data is binary or one if the node data is a string. Other values of wType are reserved for future use. The rest is the same as before: A null-terminated key name, padding for DWORD alignment, the node data, more padding, and then the child nodes.

    The only change beyond the conversion to Unicode is the introduction of the wType field. This field is necessary so that the system knows whether to convert the node data from Unicode to ANSI when somebody calls the VerQueryStringA. If it's binary data, then no conversion is done; if it's string data, then the string is converted.

    We illustrate the 32-bit resource format by looking at the resources for the 32-bit shell32.dll.

    0000  98 03 34 00 00 00 56 00-53 00 5F 00 56 00 45 00  ..4...V.S._.V.E.
    0010  52 00 53 00 49 00 4F 00-4E 00 5F 00 49 00 4E 00  R.S.I.O.N._.I.N.
    0020  46 00 4F 00 00 00 00 00-BD 04 EF FE 00 00 01 00  F.O.............
    0030  00 00 06 00 35 0B 54 0B-00 00 06 00 35 0B 54 0b  ....5.T.....5.T.
    0040  3F 00 00 00 00 00 00 00-04 00 04 00 02 00 00 00  ?...............
    0050  00 00 00 00 00 00 00 00-00 00 00 00 F6 02 00 00  ................
    0060  01 00 53 00 74 00 72 00-69 00 6E 00 67 00 46 00  ..S.t.r.i.n.g.F.
    0070  69 00 6C 00 65 00 49 00-6E 00 66 00 6F 00 00 00  i.l.e.I.n.f.o...
    0080  D2 02 00 00 01 00 30 00-34 00 30 00 39 00 30 00  ......0.4.0.9.0.
    0090  34 00 42 00 30 00 00 00-4C 00 2C 00 01 00 43 00  4.B.0...L.....C.
    00A0  6F 00 6D 00 70 00 61 00-6E 00 79 00 4E 00 61 00  o.m.p.a.n.y.N.a.
    00B0  6D 00 65 00 00 00 00 00-4D 00 69 00 63 00 72 00  m.e.....M.i.c.r.
    00C0  6F 00 73 00 6F 00 66 00-74 00 20 00 43 00 6F 00  o.s.o.f.t. .C.o.
    00D0  72 00 70 00 6F 00 72 00-61 00 74 00 69 00 6F 00  r.p.o.r.a.t.i.o.
    00E0  6E 00 00 00 5A 00 32 00-01 00 46 00 69 00 6C 00  n...Z.....F.i.l.
    00F0  65 00 44 00 65 00 73 00-63 00 72 00 69 00 70 00  e.D.e.s.c.r.i.p.
    0100  74 00 69 00 6F 00 6E 00-00 00 00 00 57 00 69 00  t.i.o.n.....W.i.
    0110  6E 00 64 00 6F 00 77 00-73 00 20 00 53 00 68 00  n.d.o.w.s. .S.h.
    0120  65 00 6C 00 6C 00 20 00-43 00 6F 00 6D 00 6D 00  e.l.l. .C.o.m.m.
    0130  6F 00 6E 00 20 00 44 00-6C 00 6C 00 00 00 00 00  o.n. .D.l.l.....
    0140  74 00 54 00 01 00 46 00-69 00 6C 00 65 00 56 00  t.*...F.i.l.e.V.
    0150  65 00 72 00 73 00 69 00-6F 00 6E 00 00 00 00 00  e.r.s.i.o.n.....
    0160  36 00 2E 00 30 00 30 00-2E 00 32 00 39 00 30 00  6...0.0...2.9.0.
    0170  30 00 2E 00 32 00 38 00-36 00 39 00 20 00 28 00  0...2.8.6.9. .(.
    0180  78 00 70 00 73 00 70 00-5F 00 73 00 70 00 32 00  x.p.s.p._.s.p.2.
    0190  5F 00 67 00 64 00 72 00-2E 00 30 00 36 00 30 00  _.g.d.r...0.6.0.
    01A0  33 00 31 00 36 00 2D 00-31 00 35 00 31 00 32 00  3.1.6.-.1.5.1.2.
    01B0  29 00 00 00 30 00 10 00-01 00 49 00 6E 00 74 00  )...0.....I.n.t.
    01C0  65 00 72 00 6E 00 61 00-6C 00 4E 00 61 00 6D 00  e.r.n.a.l.N.a.m.
    01D0  65 00 00 00 53 00 48 00-45 00 4C 00 4C 00 33 00  e...S.H.E.L.L.3.
    01E0  32 00 00 00 80 00 5C 00-01 00 4C 00 65 00 67 00  2.........L.e.g.
    01F0  61 00 6C 00 43 00 6F 00-70 00 79 00 72 00 69 00  a.l.C.o.p.y.r.i.
    0200  67 00 68 00 74 00 00 00-A9 00 20 00 4D 00 69 00  g.h.t..... .M.i.
    0210  63 00 72 00 6F 00 73 00-6F 00 66 00 74 00 20 00  c.r.o.s.o.f.t. .
    0220  43 00 6F 00 72 00 70 00-6F 00 72 00 61 00 74 00  C.o.r.p.o.r.a.t.
    0230  69 00 6F 00 6E 00 2E 00-20 00 41 00 6C 00 6C 00  i.o.n... .A.l.l.
    0240  20 00 72 00 69 00 67 00-68 00 74 00 73 00 20 00   .r.i.g.h.t.s. .
    0250  72 00 65 00 73 00 65 00-72 00 76 00 65 00 64 00  r.e.s.e.r.v.e.d.
    0260  2E 00 00 00 40 00 18 00-01 00 4F 00 72 00 69 00  ....@.....O.r.i.
    0270  67 00 69 00 6E 00 61 00-6C 00 46 00 69 00 6C 00  g.i.n.a.l.F.i.l.
    0280  65 00 6E 00 61 00 6D 00-65 00 00 00 53 00 48 00  e.n.a.m.e...S.H.
    0290  45 00 4C 00 4C 00 33 00-32 00 2E 00 44 00 4C 00  E.L.L.3.2...D.L.
    02A0  4C 00 00 00 6A 00 25 00-01 00 50 00 72 00 6F 00  L...j.%...P.r.o.
    02B0  64 00 75 00 63 00 74 00-4E 00 61 00 6D 00 65 00  d.u.c.t.N.a.m.e.
    02C0  00 00 00 00 4D 00 69 00-63 00 72 00 6F 00 73 00  ....M.i.c.r.o.s.
    02D0  6F 00 66 00 74 00 AE 00-20 00 57 00 69 00 6E 00  o.f.t... .W.i.n.
    02E0  64 00 6F 00 77 00 73 00-AE 00 20 00 4F 00 70 00  d.o.w.s... .O.p.
    02F0  65 00 72 00 61 00 74 00-69 00 6E 00 67 00 20 00  e.r.a.t.i.n.g. .
    0300  53 00 79 00 73 00 74 00-65 00 6D 00 00 00 00 00  S.y.s.t.e.m.....
    0310  42 00 1E 00 01 00 50 00-72 00 6F 00 64 00 75 00  B.....P.r.o.d.u.
    0320  63 00 74 00 56 00 65 00-72 00 73 00 69 00 6F 00  c.t.V.e.r.s.i.o.
    0330  6E 00 00 00 36 00 2E 00-30 00 30 00 2E 00 32 00  n...6...0.0...2.
    0340  39 00 30 00 30 00 2E 00-32 00 38 00 36 00 39 00  9.0.0...2.8.6.9.
    0350  00 00 00 00 44 00 00 00-01 00 56 00 61 00 72 00  ....D.....V.a.r.
    0360  46 00 69 00 6C 00 65 00-49 00 6E 00 66 00 6F 00  F.i.l.e.I.n.f.o.
    0370  00 00 00 00 24 00 04 00-00 00 54 00 72 00 61 00  ....$.....T.r.a.
    0380  6E 00 73 00 6C 00 61 00-74 00 69 00 6F 00 6E 00  n.s.l.a.t.i.o.n.
    0390  00 00 00 00 09 04 B0 04                          ........
    

    As always, we start with the root node.

    0000  98 03         // cbNode (node ends at 0x0000 + 0x0398 = 0x0398)
    0002  34 00         // cbData = sizeof(VS_FIXEDFILEINFO)
    0004  00 00         // wType = 0 (binary data)
    0006  56 00 53 00 5F 00 56 00 45 00 52 00 53 00 49 00
          4F 00 4E 00 5F 00 49 00 4E 00 46 00 4F 00 00 00
                        // L"VS_VERSION_INFO" + null terminator
    0026  00 00         // padding to restore alignment
    0028  BD 04 EF FE   // dwSignature
    002C  00 00 01 00   // dwStrucVersion
    0030  00 00 06 00   // dwFileVersionMS = 6.0
    0034  35 0B 54 0B   // dwFileVersionLS = 2900.2869
    0038  00 00 06 00   // dwProductVersionMS = 6.0
    003C  35 0B 54 0B   // dwProductVersionLS = 2900.2869
    0040  3F 00 00 00   // dwFileFlagsMask
    0044  00 00 00 00   // dwFileFlags
    0048  04 00 04 00   // dwFileOS = VOS_NT_WINDOWS32
    004C  02 00 00 00   // dwFileType = VFT_DLL
    0050  00 00 00 00   // dwFileSubtype
    0054  00 00 00 00   // dwFileDateMS
    0058  00 00 00 00   // dwFileDateLS
    005C                // no padding needed
    

    As with the 16-bit version resource, the root node is always a binary node consisting of a VS_FIXEDFILEINFO. After the root node come its children.

    005C  F6 02         // cbNode (node ends at 0x005C + 0x02F6 = 0x0352)
    005E  00 00         // cbData (no data)
    0060  01 00         // wType = 1 (string data)
    0062  53 00 74 00 72 00 69 00 6E 00 67 00 46 00 69 00
          6C 00 65 00 49 00 6E 00 66 00 6F 00 00 00
                        // L"StringFileInfo" + null terminator
    007E  00 00         // padding to restore alignment
    

    The StringFileInfo contains no data, so the fact that it's string data is irrelevant. As before, the children of the StringFileInfo are language nodes.

    0080  D2 02         // cbNode (node ends at 0x0080 + 0x02D2 = 0x0352)
    0082  00 00         // cbData (no data)
    0084  01 00         // wType = 1 (string data)
    0086  30 00 34 00 30 00 39 00 30 00 34 00 42 00 30 00
          00 00         // L"040904B0" + null terminator
    0098                // no padding needed
    

    The children of the language node are the strings that make up the bulk of the version information.

    0098  4C 00         // cbNode (node ends at 0x0088 + 0x004C = 0x00D40)
    009A  2C 00         // cbData
    009C  01 00         // wType = 1 (string data)
    009E  43 00 6F 00 6D 00 70 00 61 00 6E 00 79 00 4E 00
          61 00 6D 00 65 00 00 00
                        // L"CompanyName" + null terminator
    00B6  00 00         // padding to restore alignment
    00B8  4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00
          74 00 20 00 43 00 6F 00 72 00 70 00 6F 00 72 00
          61 00 74 00 69 00 6F 00 6E 00 00 00
                        // L"Microsoft Corporation" + null terminator
    00E4                // no padding needed
    

    Notice that for string types, the cbData includes the null terminator.

    00E4  5A 00         // cbNode (node ends at 0x00E4 + 0x005A = 0x013E)
    00E6  32 00         // cbData
    00E8  01 00         // wTypes = 1 (string data)
    00EA  46 00 69 00 6C 00 65 00 44 00 65 00 73 00 63 00
          72 00 69 00 70 00 74 00 69 00 6F 00 6E 00 00 00
                        // L"FileDescription" + null terminator
    010A  00 00         // padding to restore alignment
    010C  57 00 69 00 6E 00 64 00 6F 00 77 00 73 00 20 00
          53 00 68 00 65 00 6C 00 6C 00 20 00 43 00 6F 00
          6D 00 6D 00 6F 00 6E 00 20 00 44 00 6C 00 6C 00
          00 00
                        // L"Windows Shell Common Dll" + null terminator
    013E  00 00         // padding to restore alignment
    
    0140  74 00         // cbNode (node ends at 0x0140 + 0x0074 = 0x01B4)
    0142  54 00         // cbData
    0144  01 00         // wType = 1 (string data)
    0146  46 00 69 00 6C 00 65 00 56 00 65 00 72 00 73 00
          69 00 6F 00 6E 00 00 00
                        // L"FileVersion" + null terminator
    015E  00 00         // padding to restore alignment
    0160  36 00 2E 00 30 00 30 00 2E 00 32 00 39 00 30 00
          30 00 2E 00 32 00 38 00 36 00 39 00 20 00 28 00
          78 00 70 00 73 00 70 00 5F 00 73 00 70 00 32 00
          5F 00 67 00 64 00 72 00 2E 00 30 00 36 00 30 00
          33 00 31 00 36 00 2D 00 31 00 35 00 31 00 32 00
          29 00 00 00
                        // L"6.00.2900.2869 (xpsp_sp2_gdr.060316-1512)"
                        // + null terminator
    01B4                // no padding needed
    
    01B4  30 00         // cbNode (node ends at 0x01B4 + 0x0030 = 0x01E4)
    01B6  10 00         // cbData
    01B8  01 00         // wType = 1 (string data)
    01BA  49 00 6E 00 74 00 65 00 72 00 6E 00 61 00 6C 00
          4E 00 61 00 6D 00 65 00 00 00
                        // L"InternalName" + null terminator
    01D4                // no padding needed
    01D4  53 00 48 00 45 00 4C 00 4C 00 33 00 32 00 00 00
                        // L"SHELL32" + null terminator
    01E4                // no padding needed
    
    01E4  80 00         // cbNode (node ends at 0x01E4 + 0x0080 = 0x0264)
    01E6  5C 00         // cbData
    01E8  01 00         // wType = 1 (string data)
    01EA  4C 00 65 00 67 00 61 00 6C 00 43 00 6F 00 70 00
          79 00 72 00 69 00 67 00 68 00 74 00 00 00
                        // L"LegalCopyright" + null terminator
    0208                // no padding needed
    0208  A9 00 20 00 4D 00 69 00 63 00 72 00 6F 00 73 00
          6F 00 66 00 74 00 20 00 43 00 6F 00 72 00 70 00
          6F 00 72 00 61 00 74 00 69 00 6F 00 6E 00 2E 00
          20 00 41 00 6C 00 6C 00 20 00 72 00 69 00 67 00
          68 00 74 00 73 00 20 00 72 00 65 00 73 00 65 00
          72 00 76 00 65 00 64 00 2E 00 00 00
                        // L"© Microsoft Corporation. "
                        // L"All rights reserved." + null terminator
    0264                // no padding needed
    
    0264  40 00         // cbNode (node ends at 0x0264 + 0x0040 = 0x02A4)
    0266  18 00         // cbData
    0268  01 00         // wType = 1 (string data)
    026A  4F 00 72 00 69 00 67 00 69 00 6E 00 61 00 6C 00
          46 00 69 00 6C 00 65 00 6E 00 61 00 6D 00 65 00
          00 00         // L"OriginalFilename" + null terminator
    028C                // no padding needed
    028C  53 00 48 00 45 00 4C 00 4C 00 33 00 32 00 2E 00
          44 00 4C 00 4C 00 00 00
                        // L"SHELL32.DLL" + null terminator
    02A4                // no padding needed
    
    02A4  6A 00         // cbNode (node ends at 0x02A4 + 0x006A = 0x030E)
    02A6  25 00 01 00 50 00 72 00 6F 00 64 00 75 00 63 00
          74 00 4E 00 61 00 6D 00 65 00 00 00
                        // L"ProductName" + null terminator
    02C2  00 00         // padding to restore alignment
    02C4  4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00
          74 00 AE 00 20 00 57 00 69 00 6E 00 64 00 6F 00
          77 00 73 00 AE 00 20 00 4F 00 70 00 65 00 72 00
          61 00 74 00 69 00 6E 00 67 00 20 00 53 00 79 00
          73 00 74 00 65 00 6D 00 00 00
                        // L"Microsoft® Windows® "
                        // L"Operating System" + null terminator
    030E  00 00         // padding to restore alignment
    
    0310  42 00         // cbNode (node ends at 0x0310 + 0x0042 = 0x0352)
    0312  1E 00         // cbData
    0314  01 00         // wType = 1 (string data)
    0316  50 00 72 00 6F 00 64 00 75 00 63 00 74 00 56 00
          65 00 72 00 73 00 69 00 6F 00 6E 00 00 00
                        // L"ProductVersion" + null terminator
    0334                // no padding needed
    0334  36 00 2E 00 30 00 30 00 2E 00 32 00 39 00 30 00
          30 00 2E 00 32 00 38 00 36 00 39 00 00 00
                        // L"6.00.2900.2869" + null terminator
    0352  00 00         // padding to restore alignment
    

    At offset 0x0352, we've reached the end of the ProductVersion node, the language node, and the StringFileInfo node. The next node is therefore a sibilng to StringFileInfo.

    0354  44 00         // cbNode (node ends at 0x0354 + 0x0044 = 0x0394)
    0356  00 00         // cbData
    0358  01 00         // wType = 1 (string data)
    035A  56 00 61 00 72 00 46 00 69 00 6C 00 65 00 49 00
          6E 00 66 00 6F 00 00 00
                        // L"VarFileInfo" + null terminator
    0372  00 00         // padding to restore alignment
    

    Since we haven't exhausted the VarFileInfo node, the next node is a child.

    0374  24 00         // cbNode (node ends at 0x0374 + 0x0024 = 0x0394)
    0376  04 00         // cbData
    0378  00 00         // wType = 0 (binary data)
    037A  54 00 72 00 61 00 6E 00 73 00 6C 00 61 00 74 00
          69 00 6F 00 6E 00 00 00
                        // L"Translation" + null terminator
    0392  00 00         // padding to restore alignment
    0394  09 04 B0 04   // 0x0409 = US English
                        // 0x04B0 = 1200 = Unicode UCS-2 little-endian
    0398                // no padding needed
    

    We have reached the end of the Translation node, the VarFileInfo node, and the root node. Our parsing of the version data is complete and resulted in the following version resource:

    FILEVERSION    3,0,2900,2869
    PRODUCTVERSION 3,0,2900,2869
    FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
    FILEFLAGS      0
    FILEOS         VOS_NT_WINDOWS32
    FILETYPE       VFT_DLL
    FILESUBTYPE    VFT_UNKNOWN
    BEGIN
     BLOCK "StringFileInfo"
     BEGIN
      BLOCK "040904B0"
      BEGIN
       VALUE "CompanyName", "Microsoft Corporation"
       VALUE "FileDescription", Windows Shell Common Dll"
       VALUE "FileVersion", "6.00.2900.2869 (xpsp_sp2_gdr.060316-1512)"
       VALUE "InternalName", "SHELL32"
       VALUE "LegalCopyright", "\251 Microsoft Corporation. All rights reserved."
       VALUE "OriginalFilename", "SHELL32.DLL"
       VALUE "ProductName", "Microsoft\256 Windows\256 Operating System"
       VALUE "ProductVersion", "6.00.2900.2869"
      END
     END
     BLOCK "VarFileInfo"
     BEGIN
      VALUE "Translation", 0x0409, 0x04B0
     END
    END
    

    There you have it, the format of 32-bit version resources. Future versions of Windows may extend this format, but that's what it looks like up through Windows Vista.

    Now, after all that byte-mashing, I have to confess that I've been lying to you. What you saw was not the actual version resource in shell32.dll. We'll discuss what's really going on next time.

Page 1 of 4 (32 items) 1234