How do I avoid name collision with macros defined in Windows header files?

廉价感情. 提交于 2019-12-17 19:33:09

问题


I have some C++ code that includes a method called CreateDirectory(). Previously the code only used STL and Boost, but I recently had to include <windows.h> so I could look-up CSIDL_LOCAL_APPDATA.

Now, this code:

filesystem.CreateDirectory(p->Pathname()); // Actually create it...

No longer compiles:

error C2039: 'CreateDirectoryA' : is not a member of ...

Which corresponds to this macro in winbase.h:

#ifdef UNICODE
#define CreateDirectory  CreateDirectoryW
#else
#define CreateDirectory  CreateDirectoryA
#endif // !UNICODE

The pre-processor is redefining my method call. Is there any possible way to avoid this naming collision? Or do I have to rename my CreateDirectory() method?


回答1:


You will be better off if you just rename your CreateDirectory method. If you need to use windows APIs, fighting with Windows.h is a losing battle.

Incidently, if you were consistent in including windows.h, this will still be compiling. (although you might have problems in other places).




回答2:


You could create a module whose sole purpose is to #include <windows.h> and look up CSIDL_LOCAL_APPDATA wrapped in a function.

int get_CSIDL_LOCAL_APPDATA(void)
{
    return CSIDL_LOCAL_APPDATA;
}

btw, Well done for working out what happened!




回答3:


#undef CreateDirectory




回答4:


As a developer working on a cross platform codebase, this is a problem. The only way to deal with it is to

  • ensure that windows.h is - on Windows builds at least - universally included. Then the CreateDirectory macro is defined in every one of your compilation units and is universally substituted with CreateDirectoryW. Precompiled headers are ideal for this

OR, if that is an unpleasant proposition, (and it is for me)

  • isolate windows.h usage into windows specific utility files. Create files that export the basic required functionality. The header files must use data types that are compatible with, but do NOT depend on the inclusion of windows.h. The cpp implementation file must (obviously) use windows.h.

If your utlility functions need to include project header files with conflicting symbols then the following pattern is a necessity:

#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...

You will need to then explicitly call the non macro version of any windows api functions you have #undef'd - CreateDirectoryA or W etc.




回答5:


push macro, undef it and pop the macro again:

#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
 // ...
}
#pragma pop_macro("CreateDirectory")



回答6:


Note that name conflict usually comes from a certain header file being included. Until then stuff like CreateDirectory and GetMessage isn't pulled into visibility and code compiles without a problem.

You can isolate such an inclusion into a wrapper header file and "#undef whatever" at its end. Then, whatever name collision you have will be gone. Unless, of course, you need to use those macros in your own code (yeah, so very likely...)




回答7:


You can take a back up of CreateDirectory, then undefine it, and then define it again when you finish your job with you custom one.

#ifdef CreateDirectory
#define CreateDirectory_Backup CreateDirectory
#undef CreateDirectory
#endif

// ...
// Define and use your own CreateDirectory() here.
// ...

#ifdef CreateDirectory_Backup
#define CreateDirectory CreateDirectory_Backup
#undef CreateDirectory_Backup
#endif



回答8:


#pragma push_macro("CreateDirectory")

If nothing works, instead of renaming you could use your own namespace for your functions.



来源:https://stackoverflow.com/questions/2321713/how-do-i-avoid-name-collision-with-macros-defined-in-windows-header-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!