It is typical of windows UI code to store a pointer to a C++ object into the GWL_USERDATA slot of an HWND, using code like this:
long oldValue = SetWindowLong(hWnd, GWL_USERDATA, (long) this);
And, to get it back to the winproc:
MyClass* me = (MyClass*) GetWindowLong(hWnd, GWL_USERDATA);
This is not compatible with x64: GWL_USERDATA is not even defined when building for x64. You are forced to use the GWLP_USERDATA define, which should be used with the LONG_PTR-friendly versions as follows:
LONG_PTRoldValue = SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) this); MyClass* me = (MyClass*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
This is better, but, because of issues in the header files, this can still generate portability warnings in Win32 when building with the /Wp64 switch which is enabled for 3ds Max projects now.
To obtain a clean, warning-free compile of the above code, you should write it as follows:
#if !defined( _WIN64 ) // SetWindowLongPtr() maps to SetWindowLong() in 32 bit land; react accordingly to // keep the compiler happy, even with /Wp64. LONG_PTRoldValue = static_cast<LONG_PTR>(::SetWindowLongPtr(hWnd, n, (LONG)((LONG_PTR)(ptr)))); #else LONG_PTRoldValue = static_cast<LONG_PTR>(::SetWindowLongPtr(hWnd, n, (LONG_PTR)(ptr))); #endif MyClass* me = reinterpret_cast<MyClass*>(static_cast<LONG_PTR>(::GetWindowLongPtr(hWnd, n)));
While this works, it is complicated. To simplify there are a number of functions in maxsdk\include\3dsmaxport.h which aid in portability. Using these functions we can rewrite this as:
MyClass* oldValue = DLSetWindowLongPtr(hWnd, this); MyClass* me = DLGetWindowLongPtr<MyClass*>(hWnd);
These default to GWLP_USERDATA, since this is the main reason these are used, but you can also specify it explicitly as:
DLSetWindowLongPtr(hWnd, this, GWLP_USERDATA); MyClass* me = DLGetWindowLongPtr<MyClass*>(hWnd, GWLP_USERDATA);