Nasty gotcha: The inadvertently named resource


In the resources of a Win32 module, resource files, you can identify a resource by number (ordinal) or by name (string). One horrific gotcha of the resource file format is that it doesn't require you to quote strings that are used to name resources.

Suppose you have this resource header file.

// resource.h

#define IDD_ENTERPASSWORD 100

and you use it in your resource file like this:

#include <resource.h>

IDD_ENTERPASWORD DIALOG ...
BEGIN
    ...
END

And your code tries to use the dialog like this:

DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ENTERPASSWORD),
          hwndParent, DialogProc);

Everything compiles, but the Dialog­Box function returns -1 without displaying any dialog box. Your breakpoint on the Dialog­Proc is never hit. What's going on?

What's going on is that in your resource file, you misspelled "password".

IDD_ENTERPASWORD DIALOG ...

This typo was not reported by the resource compile because of the strange rule that named resources permit but do not require quotation marks around the name. If you omit the quotation marks, the resource compile will "helpfully" insert them for you. Since IDD_ENTER­PASWORD is not defined anywhere, the resource compile assumes you meant

"IDD_ENTERPASWORD" DIALOG ...

and generates a named dialog resource called "IDD_ENTERPASWORD". If you did this on purpose, then the way you would access the dialog box would be

DialogBox(g_hinst, TEXT("IDD_ENTERPASWORD"),
          hwndParent, DialogProc);

But you didn't misspell the symbol on purpose. It was a mistake. You meant IDD_ENTER­PASSWORD. And your misspelling cost you dearly: The resource was given the wrong identifier.

Sucks to be you.

The diagnosis for this class of problems is to verify that the dialog box you describe does indeed exist.

// Diagnosing the problem: Let's see if the resource exists.
// DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ENTERPASSWORD), ...)

auto res = FindResource(g_hinst,
                        MAKEINTRESOURCE(IDD_ENTERPASSWORD),
                        RT_DIALOG);

In the debugger, check the return value of Find­Resource. If it's nullptr, then the reason the Dialog­Box function failed is that the resource didn't exist. The next step of the investigation would be to find out why the resource isn't there.

Maybe you misspelled it.

Comments (18)
  1. The MAZZTer says:

    Another option is to use a tool like this to browse your compiled resources: http://www.angusj.com/resourcehacker/

    The fact that it is using a string name instead of an int would be immediately apparent.

    1. skSdnW says:

      A problem with a lot of these tools is that they try to be helpful and display the standard ordinal types using friendly names like Bitmap and Icon without displaying actual strings with quotes so they can also add to the confusion.

    2. Awesome tool! I use it a lot.

  2. Stéphan Leclercq says:

    Welcome to the wonderful world of late binding ! This occurs in every language where the compiler allows you to use a symbol without explicitly defining it, such as Visual Basic without "option explicit".

    1. IInspectable says:

      This blog entry isn't about late binding, though. The real issue here is a permissive syntax definition, that allows to mask bugs, that the resource compiler could easily spot. In fact, the resource compiler does observe, that the symbol isn't defined and turns the wrong into... another wrong, that at least compiles. Had the resource definition syntax mandated the use of quotation marks for named resources, this typo wouldn't have made it into the final executable.

      1. Stéphan Leclercq says:

        Actually, your method would only catch the case where the name was mis-typed while using a #define to map a numeric value. If your application uses string-named resources instead of numbered ones (mine do...), merely quoting them would not catch the error.
        If, on the contrary, defining a resource would emit a named symbol in an obj-like file, a name mismatch would lead to either the c file not compiling, or the exe not linking... (note that i'm not advocating the "if it links, ship it!" method of development)

  3. Brian_EE says:

    Another reason not to hand type items #define'd in header files. The editor I use allows me to double-click a word/keyword/string/number and select the whole text piece. Ctrl-C, Ctrl-Tab (to switch child window), Ctrl-V and I know that the identifier is correct. If it's more than four or five letters, this is my routine.

  4. skSdnW says:

    Another surprising thing about the resource compiler is that Foo is not the same as "Foo". It will actually store the string WITH quotes in the PE resource section. This means that a .rc file can contain Foo and "Foo" as separate named resources!

    1. Oh, ouch! That totally ruins my idea that rc could have a "strict" mode where it required the quotes for stringy resource names. I guess a "no stringy resource names" flag would still be possible, though...

  5. Ken Hagan says:

    I've seen named resource types, but I've never seen named resources in the wild. Did anyone *ever* use this feature, or has it always just been an irritation for Win32 programmers? Why are the APIs even designed this way? Why did anyone ever think that resources (baked, as they are, into the executable by the original programmer) should be addressed by anything more cumbersome than a small integer?

    1. alegr1 says:

      I'm actually using them in my current project. To include named files as resources.

    2. xcomcmdr says:

      I prefer naming things that use integers. It's way more easy to remember when you need the resource..

    3. GregM says:

      Yes, I've used named resources in production code. With MFC, you can load multiple resource DLLs that share identifier space. You make any one of them active at any one time, and that's where lookups go first. It's very hard to avoid resource conflicts when third party plugins are involved. There were resources that I needed to be able to load even when the default resource DLL was one provided by a third party.

  6. Henri Hein says:

    I have run into this several times over the years. It's annoying, but I don't know that I would call it nasty. One small advantage to being stupid enough to repeat mistakes is that you learn to look out for it. When I see that my DialogBox call returns -1, the first thing I do is check the resource identifier.

  7. Joshua says:

    How many of you had to read this twice because it wasn't called resource.rh? I am one of them.

  8. Awesome tool! I use it a lot.

  9. Richard says:

    Who writes these by hand anyway

    1. IInspectable says:

      You'd run into the same issue, had you used an authoring tool for the resource script, only to find that typo in the resource.h file during a code review...

Comments are closed.

Skip to main content