Recently, I had to write some code that read in a bitmap from a file. For various reasons, I was not using any preexisting libraries however I was using the standard structures as defined by Microsoft.
The first issue that I noticed was that my application (which seemed fine) was crashing.
My algorithm was essentially:
- Open File (via CreateFile)
- Get Filesize of Bitmap
- Allocate enough Memory for Bitmap
- Read Entire File into Memory
- BITMAPFILEHEADER* pHeader = file In Memory;
- BITMAPINFOHEADER* pInfo = offset to Info;
- BYTE* pImageData = offset to Image Data;
I quickly checked the initial alignment of my memory buffer and of the BITMAPFILEHEADER and found both to be valid. After this I checked the header definitions of the struct BITMAPFILEHEADER which was already defined within pragma pack(2) keywords as it was only 16-bit aligned. However, the struct itself was 14 bytes in size. This left the BITMAPINFOHEADER improperly aligned as it needs to be 32-bit aligned (but was 16-bit aligned instead.)
Because the BITMAPINFOHEADER itself is properly aligned the headers for Windows CE do not specify a packing. This behavior is in fact correct, as packing the headers will cause the OS to load data into and out of the struct much slower in situations where the struct is properly aligned.
To solve this problem, we really have a two options:
- Create 2 Buffers and call ReadFile twice. One call into ReadFile reads in the initial buffer which is packed to 2-bytes. The other call reads in the BITMAPINFOHEADER and remainng data which is packed to 4-bytes. This results in two calls to ReadFile (instead of 1) but causes BITMAPINFOHEADER to be properly aligned. Accessing the 32-bit data within the BITMAPINFOHEADER will be faster, however we have to do multiple System Calls into the OS.
- Redefine (Internally not in the PUBLIC\... code) BITMAPINFOHEADER to be say BITMAPINFOHEADER_PACKED and pack it to 2-bytes to account for the 16-bit alignment caused by the 14-byte size of BITMAPFILEHEADER.