The format of bitmap resources


Another in a sporadic series on the format of Win32 resources.

Here's a question from a customer:

I'm noticing some strange behavior: When I call LoadResource then LockResource on an embedded bitmap, the data being returned by LockResource is not a properly formatted bitmap. The data is missing the BITMAPFILEHEADER, but the rest of the file is there. SizeOfResource also states that the bitmap resource is 14 bytes smaller than it actually is. 14 bytes happens to be equal to sizeof(BITMAPFILEHEADER). However, if I load the bitmap directly using LoadBitmap, everything works fine. If I look at the resource using Visual Studio, the Bitmap displays correctly and the binary data correctly includes the BITMAPFILEHEADER.

Anyone have any ideas as to why LoadResource is not correctly returning the BITMAPFILEHEADER?

Amusingly, a change to the word order changes the question to its own answer: LoadResource is correctly not returning the BITMAPFILEHEADER.

In other words, LoadResource is not stripping off the BITMAPFILEHEADER: rc.exe is.

The format of bitmap resources are pretty simple. They are just a bitmap file with the BITMAPFILEHEADER stripped off. Because it's just the file header, the thing tacked onto the front when saved as a file. It's not part of the bitmap itself. For example, if you are using a BITMAPINFOHEADER-formatted bitmap, then the resource format is a BITMAPINFOHEADER followed by the pixels.

I can't explain why Visual Studio is showing you a BITMAPFILEHEADER that doesn't exist. They're probably trying to reduce confusion for people who don't know the format of bitmap resources and wonder why the binary data doesn't match their .bmp file. Of course, in so doing, they end up creating confusion for people who do know the format of bitmap resources, or—as happened here—people who don't know the format of bitmap resources and think that the LoadResource function is messing with their bitmaps.

(For the record, the LoadResource function doesn't mess with bitmaps, icons, menus, or whatever. It just returns the raw binary data of a Win32 resource. It doesn't know the internal format of those resources any more than the file system knows the internal format of a Quicken data file or a shortcut file.)

Comments (10)
  1. Anonymous says:

    I’ve never had to use LoadResource, so I could be completely off base.

    But, don’t you need the BITMAPINFOHEADER? How are you going to determine the height and width of the bitmap, among properties, without it?

  2. Anonymous says:

    Only the BITMAPFILEHEADER is absent, the BITMAPINFOHEADER is still stored as Raymond clearly states.  "the resource format is a BITMAPINFOHEADER followed by the pixels"

  3. Anonymous says:

    This may not actually be a blogging point where individuals can enrich their learns on facilitating and leveraging .NET-related activities most effectively, but I think it’s worth mentioning that the managed API for this is Bitmap.LockBits

    Oh yeah, and since you can load PNGs and JPEGs etc with GDI+ (which is wrapped in .NET too), it makes sense that the internal memory format of the images doesn’t exactly match a BMP file format since you can load lots of other formats too…

  4. Anonymous says:

    Visual Studio likely displays the bitmap in its orignal form, before rc.exe even got a chance to touch it.

  5. Anonymous says:

    The file header is useless anyway. The only things it contains:

    The magic number "BM" which is a) redundant with the file extension and b) unreliable as a way of checking the file type. Since any normal text file could begin with this (like "BM is the magic number used in …") everyone uses the extension anyway.

    The file size. The file system already knows this. Having a field in the header only adds a chance to get it wrong.

    The bitmap data offset. Unnecessary, since in principle you could simply fix this to be right after the headers. I’ve seen various programs fail to look for the bitmap bits in the right place because the data offset had a non-standard value. Again, this field just adds another chance to get it wrong.

  6. Anonymous says:

    @Anonymous Coward:

    I think the entire BMP format was (or rather format*s* were) designed (or rather evolved) to provide the maximum number of opportunities for things to go wrong.

    You’re assuming the purpose of the format is to contain image data rather than to be a puzzle for programmers. :-)

  7. Anonymous says:

    You might have a small typo there.

    s/and more/any more/

    It’s still amusing to hear how there is a perfectly logical explanation to a question like this.

    [Fixed, thanks. -Raymond]
  8. Anonymous says:

    @Leo

    Reminds me of packed bitmaps. Obviously, Windows knows how to compute the pointer to the pixel data in a packed bitmap. But since they don’t expose it, you have to do the computation yourself in order to use any of the bitmap functions. I doubt there is a single implementation that does it correctly for all flavors of bitmaps, taking into account different types of headers, various ways to specify the length of the color table, optional bit masks, RGBQUADs vs. RGBTRIPLEs, and so on.

  9. Erzengel says:

    @Ben Voigt: Thanks for clearing that up, I completely misunderstood that. My bad.

  10. Anonymous says:

    The RC compiler does even funkier things to Icons and Cursors, effectively turning a single file into multiple resources.   It doesn’t just strip the file header from .cur and .ico files.  It actually throws it away and makes a completely different one.

    [Hi, John, good to see you again. You’re jumping the gun; I haven’t gotten to icons and cursors yet in my series on resource formats. -Raymond]

Comments are closed.