I have a top-down device-independent bitmap in a file and use LoadImageW()
to load it and get a handle.
In Windows 7, the bitmap loaded fine. In Windows 10 and 11, loading the same bitmap returns a NULL handle, and sets the last error to zero. My understanding is that this indicates an invalid bitmap.
If I convert the bitmap file into a bottom-up bitmap, Windows 10 loads it just fine.
For the record, bottom-up bitmaps are standard Windows format -- the first row of pixels in the bitmap is the bottom-most row. Top-down bitmaps are inverted, and the first row of pixels is the top-most row. This is indicated by a negative biHeight
member in the BITMAPINFOHEADER
structure.
As I said, LoadImageW()
in Windows7 loaded both bottom-up and top-down bitmaps without any problem. Windows 10 seems to consider top-down bitmaps (which happens to be the OS/2 format but is documented by Microsoft) invalid.
I can't find anything in the documentation that states top-down bitmaps are no longer supported.
I created a test Visual Studio project with a C++ program to demonstrate the problem, along with identical top-down and bottom-up bitmaps and, the first time I posted this question. I provided this via a link, but that post was deleted for "violating standards". Presumably linking isn't allowed, but there doesn't seem to be any way to provide a zip file, and I can't upload a BMP file either. I will, however, post the test program here. To reproduce the problem, just replace the bitmap with a top-down bitmap and you'll see it fails on Windows 10 and Windows 11, but works fine on Windows 7.
// TestProgram.cpp : Demonstrate that LoadImage() on windows 10
// fails with top-down bitmaps but Windows 7 succeeds.
#include <windows.h>
#include <tchar.h>
int main()
{
for (int i = 0; i < 2; ++i)
{
const LPCWSTR psz_filename = (i == 0)
? L"bitmap-bottom-up.bmp"
: L"bitmap-top-down.bmp";
const HANDLE h_bit_map
= LoadImage(nullptr, psz_filename, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (h_bit_map == nullptr)
{
// An "invalid" bitmap does not call SetLastError()
// if (GetLastError() == NO_ERROR)
// SetLastError(ERROR_INVALID_DATA);
const DWORD dw_last_error = GetLastError();
LPWSTR sz_msg_buf{};
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
nullptr, dw_last_error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// LPWSTR cast required (see docs)
reinterpret_cast<LPWSTR>(&sz_msg_buf), 0, nullptr);
fwprintf_s(stdout, L"%s: LoadImage API call failed to return a handle;\n"
"\tGetLastError = %d %s\n",
psz_filename, dw_last_error, sz_msg_buf);
LocalFree(sz_msg_buf);
DeleteObject(h_bit_map);
}
else
(void) fwprintf_s(stdout, L"%s: LoadImage API call succeeded!\n", psz_filename);
}
return (0);
}
The output on Windows 7:
.\TestProgram.exe
bitmap-bottom-up.bmp: LoadImage API call succeeded!
bitmap-top-down.bmp: LoadImage API call succeeded!
The output on Windows 10 and 11:
.\TestProgram.exe
bitmap-bottom-up.bmp: LoadImage API call succeeded!
bitmap-top-down.bmp: LoadImage API call failed to return a handle;
GetLastError = 0 The operation completed successfully.
Note that the top-down bitmap did NOT return a handle, but also did not set the last error code. This is apparently the expected behavior when LoadImageW()
is called with an invalid bitmap. I would have expected ERROR_INVALID_DATA
instead.
If nobody knows whether top-down bitmaps are no longer supported, I'll raise a support incident. Just seems like this would have been detected a long time ago.