Hello All, I will apologize in advance for a confusing/strange question here...
I am using a FileSystem interface that is defined in my project. That interface has a method exposed called GetFileAttributes( const wchar_t* pszPath, unsigned int dwAttributes ). When I am using this interface and the GetFileAttributes method, the compiler translates FileSystem->GetFileAttributes( ) to FileSystem->GetFileAttributesW( ). I think the issue is that it by default is translating that because I have the preprocessor defines UNICODE and _UNICODE defined.
Here's my compiler output:
.\main.cpp(817) : error C2039: 'GetFileAttributesW' : is not a member of 'XXFileSystem'
1> c:\xx\source\projects\interfaces\xx\XXFileSystem.h(74) : see declaration of 'XXFileSystem'
1>.\main.cpp(823) : error C2039: 'GetFileAttributesW' : is not a member of 'XXFileSystem'
1> c:\xx\source\projects\interfaces\xx\XXFileSystem.h(74) : see declaration of 'XXFileSystem'
When I see the declaration of 'XXFileSystem', GetFileAttributes is clearly defined. Also, I know that's not the issue because other modules in my project do the exact same thing, with the exact same code and get no compiler errors.
The error must be with a visual studio project setting... but which!?!!?
It's not a project setting. This is a problem caused by <windows.h> macros polluting the global namespace.
What's basically happening is this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// your class
class MyClass
{
void GetFileAttributes();
};
// include windows...
#include <windows.h>
// note: windows.h has the below line
#define GetFileAttributes GetFileAttributesW
// then in your code:
MyClass foo;
foo.GetFileAttributes(); // ERROR, because the macro substitution replaces
// this with GetFileAttributesW, but the class has no GetFileAttributesW
Solutions here are:
1) Don't include windows.h
2) Rename your class functions so they don't clash with windows macros
3) #undef affected windows macros.
I don't really reocmmend #3 unless there is absolutely no way you can do the other 2.
Hey Disch, I don't think any of those solutions will work for me. #1 because I definitely will have to include windows.h (it's a really big system, and somewhere in my module I guarantee I will rely on it). #2 I can't rename my class functions because this interface has been in place for 8+ years and I'm not changing it now. #3 because I just don't like the idea of #undefing that if there's some other way.
Other modules in my solution (visual studio) don't have this issue. The code is pretty much copy and pasted. Can you think of anything else that could be going on here? Something I'm not including? Or some preprocessor define I should or shouldn't have? Anything in project settings? I'm still investigating but I figured I'd consult the guru :P
Well the problem might only surface if you're inconsistent with how <windows.h> is included.
For example... if you always #include windows.h before you include xxfilesystem.h, then you might not ever see the problem, because the macro mangling will change XXFileSystem::GetFileAttributes to XXFileSystem::GetFileAttributesW, which will hide the problem.
However that's only true if every file that uses xxfilesystem includes windows.h first. But personally I'd rank this solution even below the #undef solution in terms of cleanliness and consistency.
Can you think of anything else that could be going on here? Something I'm not including? Or some preprocessor define I should or shouldn't have? Anything in project settings?
I'm pretty sure there isn't any extra include that will help.
Nothing in project settings will help either.
There might be an extra #define you can make before including windows.h to prevent it from making all these macros (I know there's one to stop it from defining MIN and MAX), but I find it a bit unlikely because such a macro would effectively change the entire API.
I was calling this interface from main.cpp of my application which has to include windows.h. I wrote a global (to my module) function that grabs the file system interface and calls GetFileAttributes in a scope where windows.h is not included. That solved my problem.
Follow up question:
If I make that global function inline will I get the same error?
It depends entirely on where windows.h is included in relationship to the GetFileAttributes call.
Remember that the issue is due to a #define doing a substitution on that token. So any time 'GetFileAttributes' is seen after you #include windows.h, it will be replaced with GetFileAttributesW.
If your global function is inlined before windows.h is included, you're fine, because the macro hasn't been defined yet. But if it's after, you'll have the same problem.