The relationship between module resources and resource-derived objects in 16-bit Windows


As we saw last time, in 16-bit Windows, resources attached to an EXE or DLL file (which I called module resources for lack of a better term) were recorded in memory as discardable global memory blocks, and the window manager accessed them directly as needed. For example, if you had an icon or a cursor, the HICON or HCURSOR was really a resource handle, and when the window manager needed to draw the icon or cursor, it would cast the icon or cursor handle to a global handle (since that's what it was under the hood), then call Lock­Resource to access the raw resource data in order to copy the pixels onto the screen.

Similarly, accelerator tables were simply locked and accessed directly.

On the other hand, some resources were actually templates for other objects. As suggested by their names, dialog and menu templates were just the blueprints for creating a dialog or menu. When you called Create­Dialog or Load­Menu, the template was read from memory, and a fresh new dialog or menu was created based on the template. Once that was done, the template was no longer used. You could modify the resulting dialog or menu all you want, and you were also on the hook for making sure it is destroyed. (Either by destroying it yourself or by transferring that obligation to somebody else.)

Bitmap resources worked the same way. The resource data is a template for a new bitmap, and each time you called Load­Bitmap (or one of its moral equivalents), a brand new bitmap was created using the resource as a template. Once that was done, the template was no longer used, and you could modify the copy to your heart's content. (And you were also responsible for destroying it when you were done.)

String resources were typically copied out of the resource section, either by the Load­String function or explicitly by your custom string extractor. The lifetime of the copied string was therefore controlled by you, and you could modify the copied string all you like since it was just a copy.

If your custom string extractor simply returned a direct pointer to the resource rather than copying, then the pointer became invalid when the module was unloaded.

Okay, let's summarize in a table:

16-bit Resources
Resource type Operation Result
Icon Load­Icon, etc. Reference
Cursor Load­Cursor, etc. Reference
Accelerator Load­Accelerator, etc. Reference
Dialog Create­Dialog, etc. Copy
Menu Load­Menu, etc. Copy
Bitmap Load­Bitmap, etc. Copy
String Load­String Copy
String Find­Resource Reference

Some of these rules changed in the conversion from 16-bit Windows to 32-bit Windows, but in a way that tried to preserve the semantics of the operations. We'll look at those changes next time.

But even before you get to that article, you have enough information to answer this customer's question:

How do I recover the dialog ID from a dialog if I have the dialog's window handle?

This is like asking, "How do I recover the recipe book that a particular cake was made from?" The cake does not know what recipe book it was made from. You might be able to do a chemical analysis followed by a thorough survey of all cookbooks in existence to try to find a match, but even if you do, it's merely a best-guess. (And if the dialog was modified after being created, then you will never find a match. Just like you will never find a cake recipe match if somebody decided to modify the cake after it came out of the oven.)

Comments (6)
  1. Well, the obvious way would be to enumerate through the dialog resources and compare the window and all child windows with the DIALOGTEMPLATE(EX) and all of the DIALOGITEMTEMPLATE(EX) structures that follow it.

    If comparing these gives a match (taking into account things like the conversion of the dialog unit/pixel conversion, the x and y point of the window changing, and if the window is resizable, the width and height changing and the contents of certain controls changing like edit controls and check/radio buttons) then you can return it as a possible ID.

    But you would also have to be aware of the possibility of coincidentally very similar dialog resources and other complications like this.

  2. I forgot to mention, you could also mention that they could help themselves by adding the dialog template as a window property in WM_INITDIALOG if it is important. This way, instead of guesswork, you can recover the ID with very high certainty.

    [This question is usually asked in the context of some sort of tool that is trying to identify windows it didn't create. For example, a macro recorder or a localization verification tool. -Raymond]
  3. Ah LoadString. Why was there never a LoadString variant that allowed loading from a specific language table? I had to manually traverse the string table to get a string from a different language.

  4. @Georg_Rottensteiner:

    Vista added native handling for this. This is why you see those language directories around in places with the .mui files in them. The resource loading functions look in the module resource table, notice that it is a language neutral resource, then redirects to the preferred UI language directory to load the corresponding .mui file.

    For earlier versions of Windows, this is why applications used satellite libraries as resources.

  5. Alex Cohn says:

    @Georg_Rottensteiner:

    Because string table is not the only <s>language</s> culture dependent resource. Dialog templates, menus, bitmaps, icons, accelerators, whatnot…

  6. ender says:

    While it's nice that Windows allows all kinds of resources to be localized, it's handling of localized strings leaves a lot to be desired (at least if you're not localizing to English).

Comments are closed.