当包含Windows.h时,导致错误A不是B的成员

时间:2016-05-05 23:59:51

标签: c++ include

以下代码是我的包含文件:

Include files

但是,我发现当我使用#include <Windows.h>时,项目无法编译,它会出错:

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

在这一行:

im.LoadImage("bg.png");

但是,如果我不使用#include`,一切正常。任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:2)

这是Win32 API的常见问题,会影响与支持TCHAR数据的Win32 API函数同名的任何符号。

在这种情况下,Windows.h包含winuser.h,它定义了Win32 API LoadImage()函数,如下所示:

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

#define语句是造成问题的原因。 #define在范围上是全局的,并不尊重文件边界,名称空间,类定义等。它只是一个直接的文本替换。所以,当你的代码调用它时:

im.LoadImage("bg.png");

预处理器将其更改为以下内容,这是编译器看到的内容:

im.LoadImageA("bg.png");

或者:

im.LoadImageW("bg.png");

取决于您是为MBCS还是Unicode编译项目(在这种情况下,您使用的是MBCS)。

如果微软对C ++开发人员更好,Win32 API头文件将使用内联函数而不是C宏,例如:

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++

这将允许适当的范围和重载跨库,类等重复的任何名称。但是,唉,微软似乎不愿意这么多年后这样做:( Win32 API主要是为C和其他C兼容语言设计的,它为C ++提供的条款很少(不包括GDI +,COM等)。

在任何情况下,对于您的情况,最简单的解决方案是:

  1. ImageData.LoadImage()方法重命名为更独特的名称。

  2. 使用#undef LoadImage语句(假设您不需要在源文件中的任何其他位置使用实际的Win32 API LoadImage()函数):

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

    或者,如果你想要更具限制性:

    #ifdef _WINUSER_
    #undef LoadImage
    #endif
    
    im.LoadImage("bg.png");
    

答案 1 :(得分:0)

LoadImage是Windows.h内的一个宏。它会将该文本的任何和所有出现重写为LoadImageW或LoadImageA。因此你的问题。您需要为您的内容选择不同的名称或暂时#undef