views:

265

answers:

5

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?

+8  A: 

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

John Knoeller
+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.
Len Holgate
+4  A: 

#undef CreateDirectory

rerun
+6  A: 

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!

quamrana
Clever solution.
Mark Ransom
A: 
#pragma push_macro("CreateDirectory")

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

AureliusMarcus
A namespace will not fix this problem. The preprocessor is renaming his CreateDirectory method to something else.
caspin
You are right, I got the issue wrong. My solution was just some poor alternative to renaming.
AureliusMarcus
A: 

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.

Chris Becke