Why can’t I create my dialog box? Rookie mistake #1


Each dialog box resource is specified either by an integer ordinal or by a string name. But a simple typo will turn one into the other.

#define DLG_OPEN 1
#define DLG_WARN_REMOVEABLE 2

DLG_OPEN DIALOG 32, 32, 267, 73
...
BEGIN
  ...
END

DLG_WARN_REMOVABLE DIALOG 32, 32, 267, 73
...
BEGIN
  ...
END

DialogBox(hInstance, TEXT("DLG_OPEN"),
          hwnd, OpenDialogProc);

DialogBox(hInstance, MAKEINTRESOURCE(DLG_WARN_REMOVEABLE),
          hwnd, WarnRemoveableDialogProc);

Do you see the two "classic rookie mistakes"?

It may be easier to spot if you take the resource file and send it through the preprocessor first:

1 DIALOG 32, 32, 267, 73
...
BEGIN
  ...
END

DLG_WARN_REMOVABLE DIALOG 32, 32, 267, 73
...
BEGIN
  ...
END

The first call to DialogBox passes TEXT("DLG_OPEN") as the resource name. But notice that there is no resource with that name. The preprocessor turned DLG_OPEN into 1 thanks to the line #define DLG_OPEN 1 in the header file. Therefore, the call to DialogBox fails since there is no dialog box named DLG_OPEN. The dialog box you want goes by the integer name 1.

DialogBox(hInstance, MAKEINTRESOURCE(DLG_OPEN),
          hwnd, OpenDialogProc);

The second mistake is more subtle. Notice that the name of the second dialog is spelled inconsistently. The header file calls it DLG_WARN_REMOVEABLE, but the resource file calls it DLG_WARN_REMOVABLE. As a result, the preprocessor macro is not invoked, and the result is a dialog that goes by the string name TEXT("DLG_WARN_REMOVABLE"). However, the code asks for MAKEINTRESOURCE(DLG_WARN_REMOVEABLE), which doesn't exist.

To fix the second issue, you first have to decide what you really wanted. You probably wanted an integer dialog resource, in which case the fix is to correct the resource file:

DLG_WARN_REMOVEABLE DIALOG 32, 32, 267, 73

On the other hand, if you really wanted the dialog box to be a named resource (note: this is extremely rare), then you need to request it by name:

DialogBox(hInstance, TEXT("DLG_WARN_REMOVABLE"),
          hwnd, WarnRemoveableDialogProc);

We'll look at a few more "rookie mistakes" over the next couple of days.

Comments (21)
  1. required says:

    I’m curious: why was the decision made to allow creation by ordinal or string?

    [I don’t know. Each method has its own advantages and disadvantages. I thought you folks liked it when Windows had more settings and options? -Raymond]
  2. Stu says:

    @required: Probably because it was originally ordinal only, because in 1985 those few bytes to store a string would have made Windows 1.0 require more than 256kb of RAM. Or something along those lines.

    Doesn’t it just seem that each new version of Windows becomes more and more hobbled by 10-20 year old design decisions?

    Maybe if the .Net CLR was implemented as an NT subsystem, rather than a wrapper around Win32, we would have some way of escaping the insanity and backwardness of Win32, but no sign of that happening any time soon.

  3. GregM says:

    When creating a property sheet using pages that have resources from multiple DLLs, you need to reference them by name instead of by ordinal, or you can get the wrong dialog resources because of duplicated ordinals.

    (This is from experience, it actually happened to me.)

  4. Jack Mathews says:

    Raymond, I’m curious why the convention is to prefer ordinals over strings?

    I mean, the lookup cost is negligable, is it more so that people don’t try to hook into standard windows DLLs for their resources?  Or is it one of those “we do it because that’s how we’ve always done it” types of things?

    [A floppy disk access is not negligible. -Raymond]
  5. Tim says:

    "Doesn’t it just seem that each new version of Windows becomes more and more hobbled by 10-20 year old design decisions?"

    You’re so right.  Vista is completely hobbled because a developer has 2 ways of specifying a resource.  I don’t know how any programs ever manage to run at all!

  6. So: what are the advantages and disadvantages of each method?

    [I intentionally left that as an exercise for the reader. -Raymond]
  7. mikeb says:

    I ran into this recently because I was messing around with a CBitmapButton.  The docs have this to say:

    ===================================

    You must specify the ID of your bitmaps within double quotes. Otherwise the resource editor will assign an integer to the resource and MFC will fail when loading the image

    ===================================

    I really had no idea what they were talking about, and the resource compiler didn’t like it when I put double quotes around the ID in the .rc file.

    I finally stumbled on what was intended by the CBitampButton docs.  The key is "the resource editor".  When you’re editing the .rc file using Visual Studio’s resource editor instead of editing the .rc file directly in a text editor, you get the desired behavior: when the ID is in quotes in the VS resource editor dialog, VS doesn’t add a "#define" for it in resource.h, otherwise it does.

    I suppose that’s what I get for avoiding UI programming for most of the past 15+ years.

  8. mikeb says:

    > "Doesn’t it just seem that each new version of Windows becomes more and more hobbled by 10-20 year old design decisions?"

    You’re so right.  Vista is completely hobbled because a developer has 2 ways of specifying a resource.  I don’t know how any programs ever manage to run at all! <<

    Maybe ‘hobbled’ is the wrong word, but clearly Windows is a more complex beast because of design decisions made long ago.  In fact, that’s often an important point of Raymond’s daily postings.

    Not to say that this complexity was avoidable; after all, Raymond has yet to invent the time machine.  But that’s on the schedule for Longhorn Server, right?

  9. Frank Richter says:

    String names could perhaps have been better integrated syntax-wise: if a resource is to be named by a string instead of ordinal require the string to be "quoted". So a token being skipped by the preprocessor would still be caught by the parser, complaining about the lack of quoting…

    Alas, too late now :) …though it could still be added into the resource compiler. Of course that would give suddenly a lot of trouble with the existing corpus of resource scripts.

  10. Mike Dimmick says:

    mikeb: That’s because there are features in CBitmapButton that cause it to append a character to the string you provide, to find different images for ‘hot’ (user is hovering over button), pressed and disabled buttons. Yes, this is pretty lame. You could do the same with ordinal-based resources, but it’s a little trickier to ensure that the images have sequential resource IDs.

    Alternatively they could have required that the bitmap was four times as big as a single button image, and sliced the bitmap appropriately. However, CBitmapButton was designed for (you guessed it) Windows 3.x, where the size of the GDI resource heap was only 64KB, so I’m guessing that making the bitmap larger and slicing it would have wasted GDI resources unnecessarily.

  11. Foolhardy says:

    Stu: Making .NET independent of Win32 would be lovely. I think something similar may have been happening prior to the "Longhorn reset".

    It seems that NT is doomed to be a platform just to support Win32 for the rest of its lifetime. It’s a shame too, NT is in many ways the most advanced general purpose kernel and system available today, but it’s only available via Win32.

    Win32 is certainly usable, but it has accumulated so many special cases, gotchas, redundant and counter-intuitive behaviors from compatibility, mistakes (both from ISVs and MS) and lack of foresight that it can be a real pain to use effectively.

    The fact that it’s even possible to make such a mistake so easily is a failure of the API. We’ve had better type checking available for a long time, and other APIs (like .NET’s) use them. For that matter, didn’t we determine that macros were evil a long time ago– that compiler constants were much better? Why is this still the primary method for writing Windows apps in 2007?

  12. Good Point says:

    "Why is this still the primary method for writing Windows apps in 2007?"

    Because Microsoft highly values backwards compatibility (and A floppy disk access is not negligible).

  13. Dean Harding says:

    Wow, how did we jump from being able to specify string-based or ordinal-based resource names to the “death of Win32”?

    [You must be new here. -Raymond]
  14. Jug says:

    Haha, this preprocessor thing reminds me of a mistake I did once by subtracting one #defined value ("X") from another ("Y") and the latter was in turn defined as "A – B"…

    I just saw the calculation as DEF_X – DEF_Y (i.e. really DEF_X – (DEF_A – DEF_B)), but in reality of course got DEF_X – DEF_A – DEF_B. :-p

  15. Hamilton Lovecraft says:

    Raymond Chen: “Today in The Old New Thing, I’m once again going to be throwing bloody chunks of fish guts off the back of the boat!”

    random commenter: “I’m a shark! RAAAARRR!” *CHOMPCHOMPCHOMP*

    Chen: “I really don’t understand why these sharks keep attacking the boat!”

    [It hadn’t occurred to me that grayscale algorithms are inflammatory. I’ll try to avoid them in the future. -Raymond]
  16. Foolhardy says:

    Re: Dean Harding: *sigh* It just seems like Win32 has become the elephant in the room that no one wants to talk about, and it’s dragging the quality of Windows down. There are new and good things happening in Windows development, but we can’t quite make the shift over to them, even for 100% new programs. We still have to deal with pre-processor issues from 20 years ago.

    The fact that Win32 permeates even .NET, what should be a clean start API wise, and the fact that Win32 is still the only game in town for many functions is holding Windows back.

    It’s possible to build a clean, modern API alongside Win32 (NT was designed to operate parallel APIs), but instead we’re stuck in the past and it’s frustrating.

    Larry and Raymond keep warning us about specific pitfalls and peculiarities (enough to publish a book about it!), and the overall conclusion some of us come to is that Win32’s time has passed to be the primary API of a modern OS– for the total of the myriad reasons they outline in articles like this one.

    [Could we stick to the topic, please? If you want to debate the future of Win32 please do it on your own site. -Raymond]
  17. Prvn says:

    accidently, i saw this blog. I really liked the way you present the so-called "old new" things!!! (even though, i cudnt understand many old and new things. See, am a beginner). I will be watching you…  

  18. True #1 says:

    Rookie mistake of all times must be forgetting setting style visible=true when changing from modal (DialogBox) to modeless (CreateDialog), and the dialog does not appear visible.

  19. Mike says:

    I think the reason there are both numerical and string ID’s are obvious. The string representation allows for more dynamic runtime behaviour, at the expense of size and speed, while the efficient numerical (binary) representation means both implementations (both the PE exporting the resource and the PE(s) importing it) are binary linked at the hip.

    Just compare it to linking a DLL (or other PE exporting symbols) by name or ordinal. Especially with C++ name mangling you can pay a *serious* overhead for exporting by name with the MS-compilers C++ name mangling if you ex/import by name instead of by ordinal. I’ve myself seen a DLL with carefully and properly applied ordinal-only exports shrink to one third (!) vs. using the compiler-generated names. I can imagine the MFC with its number of export (is it in the range of 7000 or so?) would reach almost astronomical size had it not exported by ordinal only. While this obviously is an extreme compared to the (likely) avg. growth of DLL size using string or ordinal im/export from/to resources, the concept is still the same.

  20. Neil says:

    required: Don’t forget that you can define your resource by ordinal but reference it by string (such as that obvious #32770 class name).

  21. David Pritchard says:

    I guess the point of referencing dialogs by string is that it’s easier to avoid conflicts. IDs conflict very easily, especially if you’ve got multiple resource DLLs flying around the place.

Comments are closed.

Skip to main content