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

8

22

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?

Stringfellow answered 23/2, 2010 at 21:7 Comment(3)
Now you know why Bjarne Stroustrup wants to get rid of the C pre-processor from C++ -- see 'Design and Evolution of C++'.Mcghee
Possible duplicate with answers: #1395410Hildegard
Please vote this up: visualstudio.uservoice.com/forums/121579-visual-studio/…Railing
W
16

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

Workday answered 23/2, 2010 at 21:9 Comment(2)
+1 for consistently including windows.h and, if I could, +1 for not fighting it and renaming to avoid... I had this problem with InitiateShutdown() and all attempts to work around just caused new problems.Erv
Sometimes it's hard to find a better name other than the name taken by MS.Tong
M
10

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!

Moonlight answered 23/2, 2010 at 21:24 Comment(0)
S
9

#undef CreateDirectory

Sperrylite answered 23/2, 2010 at 21:10 Comment(0)
R
3

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.

Richert answered 24/2, 2010 at 8:0 Comment(0)
G
2

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
Galanti answered 13/8, 2018 at 8:34 Comment(0)
F
1

push macro, undef it and pop the macro again:

#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
 // ...
}
#pragma pop_macro("CreateDirectory")
Feoffee answered 14/1, 2017 at 16:23 Comment(0)
I
0

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

Impercipient answered 10/2, 2017 at 16:21 Comment(0)
P
-2
#pragma push_macro("CreateDirectory")

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

Puppy answered 23/2, 2010 at 22:11 Comment(3)
A namespace will not fix this problem. The preprocessor is renaming his CreateDirectory method to something else.Peccavi
You are right, I got the issue wrong. My solution was just some poor alternative to renaming.Puppy
You should delete your answerDwaindwaine

© 2022 - 2024 — McMap. All rights reserved.