When include Windows.h causes the error A is not a

2019-02-27 19:23发布

The following code are my include files:

Include files

However, I find that when I use #include <Windows.h>, the project can not compile, it will come with an error:

"LoadImageA": is not a member of "ImageData"

On this line:

im.LoadImage("bg.png");

However, if I do not use #include `, everything works fine. Can any one help me?

标签: c++ include
2条回答
唯我独甜
2楼-- · 2019-02-27 20:04

This is a common problem with the Win32 API, and affects any symbols that have the same name as Win32 API functions that support TCHAR data.

In this case, Windows.h includes winuser.h, which defines the Win32 API LoadImage() function as follows:

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);
#ifdef UNICODE
#define LoadImage  LoadImageW
#else
#define LoadImage  LoadImageA
#endif // !UNICODE

The #define statements are what is causing your problem. A #define is global in scope, and doesn't respect file boundaries, namespaces, class definitions, etc. It is just a straight text replacement. So, while your code is calling this:

im.LoadImage("bg.png");

The preprocessor changes it to the following, which is what the compiler sees:

im.LoadImageA("bg.png");

Or:

im.LoadImageW("bg.png");

Depending on whether you are compiling your project for MBCS or Unicode (in this case, you are using MBCS).

If Microsoft would be nicer to C++ developers, the Win32 API headers would use inline functions instead of C macros, eg:

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);

#ifdef __cplusplus
inline HANDLE LoadImage(
    __in_opt HINSTANCE hInst,
    __in LPCTSTR name,
    __in UINT type,
    __in int cx,
    __in int cy,
    __in UINT fuLoad)
{
  #ifdef UNICODE
  return LoadImageW(hInst, name, type, cx, cy, fuLoad);
  #else
  return LoadImageA(hInst, name, type, cx, cy, fuLoad);
  #endif // !UNICODE
}
#else
  #ifdef UNICODE
  #define LoadImage  LoadImageW
  #else
  #define LoadImage  LoadImageA
  #endif // !UNICODE
#endif // !C++

That would allow proper scoping and overloading of any names repeated across libraries, classes, etc. But alas, Microsoft seems unwilling to do that after all these years :( The Win32 API is primarily designed for C and other C-compatible languages, it provides very little provisions for C++ (not counting things like GDI+, COM, etc).

In any case, for your situation, the simplest solution is to either:

  1. rename the ImageData.LoadImage() method to a more unique name.

  2. use an #undef LoadImage statement (assuming you don't need to use the actual Win32 API LoadImage() function anywhere else in your source file):

    #undef LoadImage
    im.LoadImage("bg.png");
    

    Or, if you want to be a little more restrictive:

    #ifdef _WINUSER_
    #undef LoadImage
    #endif
    
    im.LoadImage("bg.png");
    
查看更多
虎瘦雄心在
3楼-- · 2019-02-27 20:08

LoadImage is a macro inside Windows.h. It will rewrite any and all occurences of that text to LoadImageW or LoadImageA. Hence your problems. You need to choose different name for your stuff or #undef it temporarily.

查看更多
登录 后发表回答