locked
Error using LoadImageW RRS feed

  • Question

  • I was using the function LoadImageW, but the image didn´t load. My code was:

    hLogoImage=(HBITMAP)LoadImageW(NULL, "fondo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

    But i decided to erase the W and just write LoadImage, and it worked.. and i don´t know why. What is the difference between LoadImageW and LoadImage and LoadImageA??

    Thursday, May 14, 2020 1:20 AM

All replies

  • The essential difference relates to the character set used for the name parameter to the functions.  The LoadImageA and LoadImageW functions are declared as follows in WinUser.h -

    WINUSERAPI
    HANDLE
    WINAPI
    LoadImageA(
        _In_opt_ HINSTANCE hInst,
        _In_ LPCSTR name,
        _In_ UINT type,
        _In_ int cx,
        _In_ int cy,
        _In_ UINT fuLoad);
    
    WINUSERAPI
    HANDLE
    WINAPI
    LoadImageW(
        _In_opt_ HINSTANCE hInst,
        _In_ LPCWSTR name,
        _In_ UINT type,
        _In_ int cx,
        _In_ int cy,
        _In_ UINT fuLoad);

    Note that the name parameter is a pointer to a wide string (LPCWSTR) in LoadImageW but is a pointer to a narrow string (LPCSTR) in LoadImageA.  The windows data types LPCWSTR and LPCSTR (see Windows Data Types) resolve to const wchar_t * and const char *, respectively.  So in your example, "fondo.bmp" is a narrow string literal while L"fondo.bmp" would be a wide string literal.

    To simplify things when using the same code for a unicode or a non-unicode build the windows headers also include the following conditional compilation statements -

    #ifdef UNICODE
    #define LoadImage  LoadImageW
    #else
    #define LoadImage  LoadImageA
    #endif // !UNICODE

    So depending on whether or not you are creating a unicode build the pre-processor resolves LoadImage to LoadImageW (for wide strings) and otherwise to LoadImageA.

    Generally, most Windows API functions that take string parameters follow the same pattern with W/A versions for unicode/non-unicode builds and corresponding pre-processor macros for conditional compilation.



    • Edited by RLWA32 Thursday, May 14, 2020 1:52 AM
    Thursday, May 14, 2020 1:47 AM
  • We rarely specify "A" or "W". As RLWA32 said, there are macros that determine which one to use. As a beginner it is likely a mistake to use the "A" or "W" version explicitly. 

    There are what are called Generic-Text Mappings. If you can get into the habit of using them then your code can be used for both ASCII and Unicode, except you must at least compile the two versions separately. For example look at strlen, wcslen, _mbslen, _mbslen_l, _mbstrlen, _mbstrlen_l. It has:

    TCHAR.H routine _UNICODE & _MBCS not defined _MBCS defined _UNICODE defined
    _tcslen strlen strlen wcslen
    _tcsclen strlen _mbslen wcslen
    _tcsclen_l strlen _mbslen_l wcslen

    So you can use _tcslen, _tcsclen or _tcsclen_l and the appropriate function will be generated in the code.

    The Generic-Text Mappings do not work for the STL and I am sure RLWA32 has guidance about that.



    Sam Hobbs
    SimpleSamples.Info

    Thursday, May 14, 2020 3:49 AM
  • In addition, LoadImage(…, “fondo.bmp”, …), which currently works, will not work if you change the “Character Set” project configuration. (For example, you switch to multilanguage Unicode applications). To cover several cases, consider this form too:

       LoadImage(…, _T(“fondo.bmp”), …).

    The next variants should also work, but probably are not recomended:

       LoadImageA(…, “fondo.bmp”, …),

       LoadImageW(…, L“fondo.bmp”, …).



    • Edited by Viorel_MVP Thursday, May 14, 2020 7:46 AM
    Thursday, May 14, 2020 7:36 AM
  • An interesting thing to remember is that C++ has up to 5 different character types.

    1) char

    Literals of this type are specified by "String Literal", no prefix.

    The type of the string literal is const char[], but it degrades (converts) to const char *.

    The encoding is dependent on system locale settings.

    Windows API functions use the A prefix to specify this type.

    2) wchar_t

    Literals of this type are specified by L"String Literal", note the L prefix.

    The type of the string literal is const wchar_t[], but it degrades (converts) to const wchar_t *.

    The size and format of this is platform dependent. Microsoft uses it as a UTF-16 type where other compilers are different.

    Windows API functions use the W prefix to specify this type.

    The next few are much newer and the Windows API doesn't have any kind of support for these.

    3) char16_t

    Literals of this type are specified by u"String Literal", note the u prefix. The case is important.

    The type of the string literal is const char16_t[], but it degrades (converts) to const char16_t *.

    This was added with the C++11 standard and up to the C++20 standard, it was heavily implied to be UTF-16. C++20 formally defined it to be UTF-16 though.

    There is no Windows API prefix for this type of character string, however on Windows it is possible to cast char16_t to wchar_t. But you have to be careful.

    4) char32_t

    Literals of this type are specified by U"String Literal", note the U prefix. The case is important.

    The type of the string literal is const char32_t[], but it degrades (converts) to const char32_t *.

    This was added with the C++11 standard and up to the C++20 standard, it was heavily implied to be UTF-32. C++ 20 formally defined it to be UTF-32 though.

    5) char8_t

    Literals of this type are specified by u8"String Literal", note the u8 prefix.

    The type of the string literal is const char8_t[], but it degrades (converts) to const char8_t *.

    This was added with the C++20 standard. Prior to C++20, the u8 prefix produced string literals of the type const char *. Because of obvious problems, the standards committee decided to add the char8_t type.

    This is formally defined to be UTF-8.

    It is quite important to remember these character types and literals since you are not always guaranteed to be using just char and "".


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.


    Thursday, May 14, 2020 8:22 AM
  • The next variants should also work, but probably are not recomended:

       LoadImageA(…, “fondo.bmp”, …),

       LoadImageW(…, L“fondo.bmp”, …).



    This is very much "it depends".

    I almost always use the W versions of the Windows API functions. If you know what you are doing and you know that you are only going to use that one string type then it isn't bad to use the functions/types explicitly.

    The generic text macros were added as a porting aid. If you were currently using the narrow character versions and at some point in the future you would be switching over to Unicode, then they would allow you to be able to do do this and have it trigger as a compile time switch. But since all this did was to use the pre-processor to convert from the generic way (LoadImage(..., _T("String"), ...)) to the explicit way (LoadImageW(..., L"String", ...)) then it is all about making all of this agree on the same type.

    I think another thing to remember is that these functions are explicitly documented. In the old version of the Windows API documentation there was a combined page with the A and W versions of the functions named. But the new version of the documentation on docs now lists LoadImageA and LoadImageW, and indeed all A and W functions, separately. So I don't believe there is any harm in explicitly calling a fully documented function.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.


    • Edited by Darran Rowe Thursday, May 14, 2020 10:30 AM
    Thursday, May 14, 2020 8:46 AM
  • > hLogoImage=(HBITMAP)LoadImageW(NULL, "fondo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

    That statement will not compile.  You'll get a type mismatch, trying to pass a "char *" to a parameter that expects wchar_t.  Was that not a clue?


    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Friday, May 15, 2020 4:59 AM