So now that we’re all convinced that the best thing to do is to pick types by following the API, let’s take a look at a place or two where that’s impossible to do right.
There are a great many reasons that I love to code to Win32. For instance, you’ve gotta hand it to an API that includes things like three-valued BOOLs. Here’s another special one.
Say you’re trying to play by the rules, so you choose to call SetWindowLongPtr() and GetWindowLongPtr() for the sake of future portability. You see that GetWindowLongPtr() returns a LONG_PTR. So, you write:
char *x = reinterpret_cast(GetWindowLongPtr(...));
…and you get this:
warning C4312: 'reinterpret_cast' : conversion from 'LONG' to 'char *' of greater size
What gives? Well, if you open up WinUser.h in the PSDK (Server 2003 R2 in my case), you will find that it only actually return ULONG_PTR if _Win64 is defined. Otherwise, it’s defined back to GetWindowLong(), which of course returns a LONG.
So, it turns out that there’s no way to avoid a compiler warning without writing non-portable code (by casting a pointer to a 32-bit value), which is exactly what we’re trying to avoid.
There is a solution, though, although it’s not particularly elegant. You can do a one-line warning suppression like so:
#pragma warning(suppress:4312) char *x = reinterpret_cast(GetWindowLongPtr(...));
The suppress pragma above disables the warning for the following source file line only. A couple of notes on that pragma: First, it is documented to only work with analysis (i.e. PREfast), but it actually works perfectly in my VC8 compiler too. Also, it is only for the following source line, not statement, so if you have multi-line statements, you have to put the pragma in the middle like so:
origWindowProc = reinterpret_cast(SetWindowLongPtr( animControl, GWLP_WNDPROC, #pragma warning(suppress:4244) #pragma warning(suppress:4312) reinterpret_cast (subclassAnimProcSt)));
You can also only disable one warning at a time with that pragma. Follow the example above to disable multiple warnings at once.
In the end, I believe it’s worthwhile to have warning-free code at the highest compiler warning levels. If you had written code using the types dictated by the standard C library (i.e. using size_t, ptrdiff_t, and so on), you would have found that the port to 64-bit code was a lot easier to deal with, and (in trivial cases) even just a recompile. Additionally, it makes it easier to spot warnings when they do happen, and it makes it easier to use static analysis tools like PREfast and PC-Lint.
My solution was to redefine the Ptr form of the functions with a inline wrapper that ignores the warnings. I consider this a bug in the Win32 headers.
#ifndef _WIN64
#pragma warning(push)
#pragma warning(disable:4244)
#ifdef GetWindowLongPtrA
#undef SetWindowLongPtrA
FORCEINLINE LONG_PTR SetWindowLongPtrA(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
{
return SetWindowLongA(hWnd, nIndex, dwNewLong);
}
#endif
…
#pragma warning(pop)
#endif //ifndef _WIN64
This is ridiculous. Why does Microsoft refuse to fix these types of issues?