3dsmaxport.h

Go to the documentation of this file.
00001 /**********************************************************************
00002  
00003    FILE:           3dsmaxport.h
00004 
00005    DESCRIPTION:    3ds max portability layer.
00006 
00007    CREATED BY:     Stephane Rouleau, Discreet
00008 
00009    HISTORY:        Created November 12th, 2004
00010 
00011  *>   Copyright (c) 2004, All Rights Reserved.
00012  **********************************************************************/
00013 #pragma once
00014 
00015 #include "utilexp.h"
00016 #include "strbasic.h"
00017 #include "BuildWarnings.h"
00018 #include <wtypes.h>
00019 #include <cmath>                    // fabs, abs.
00020 #include <cstdlib>
00021 
00022 /*
00023    Set/GetWindowLong() should never be used to store/retrieve pointers in an HWND, as
00024    they end up truncating 64 bit pointers in Win64.
00025 
00026    GetWindowLongPtr() has been introduced by MS, but they still involve a lot of 
00027    casting to properly remove warnings in Win32 and Win64.  The following inline
00028    functions are typesafe and completely inlined, to they incure no runtime hit.
00029 
00030    Instead of:
00031 
00032    IMyDataType* pData = (IMyDataType*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
00033 
00034    you should instead do:
00035 
00036    IMyDataType* pData = DLGetWindowLongPtr<IMyDataType*>(hWnd);
00037 
00038    or
00039    
00040    IMyDataType* pData;
00041    DLGetWindowLongPtr(hWnd, &pData);
00042 
00043    Similarly, instead of
00044 
00045    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pData);
00046 
00047    do
00048 
00049    DLSetWindowLongPtr(hWnd, pData);
00050 */
00051 
00052 template<typename DataPtr> DataPtr DLGetWindowLongPtr(HWND hWnd, int n = GWLP_USERDATA, DataPtr = NULL)
00053 {
00054    return (DataPtr)(static_cast<LONG_PTR>(::GetWindowLongPtr(hWnd, n)));
00055 }
00056 
00057 template<typename DataPtr> DataPtr DLGetWindowLongPtr(HWND hWnd, DataPtr* pPtr, int n = GWLP_USERDATA)
00058 {
00059    *pPtr = DLGetWindowLongPtr<DataPtr>(hWnd, n);
00060 
00061    return *pPtr;
00062 }
00063 
00064 template<> inline bool DLGetWindowLongPtr(HWND hWnd, int n, bool)
00065 {
00066    // Specialize for bool so we can quietly deal 
00067    // warning C4800: 'LONG_PTR' : forcing value to bool 'true' or 'false' (performance warning)
00068    return ::GetWindowLongPtr(hWnd, n) != 0;
00069 }
00070 
00071 inline WNDPROC DLGetWindowProc(HWND hWnd)
00072 {
00073    return DLGetWindowLongPtr<WNDPROC>(hWnd, GWLP_WNDPROC);
00074 }
00075 
00076 inline HINSTANCE DLGetWindowInstance(HWND hWnd)
00077 {
00078    return DLGetWindowLongPtr<HINSTANCE>(hWnd, GWLP_HINSTANCE);
00079 }
00080 
00081 // Type can be either pointer-sized, or not.  So we'd need either static_cast<> or
00082 // reinterpret_cast<>.  It's simpler here to force using a C cast than going through
00083 // a tag-based solution, such as used by std::distance to pick between random-iterator
00084 // and forward-iterator types.
00085 template<typename Type> inline Type DLSetWindowLongPtr(HWND hWnd, Type ptr, int n = GWLP_USERDATA)
00086 {
00087 #if !defined( _WIN64 )
00088    // SetWindowLongPtr() maps to SetWindowLong() in 32 bit land; react accordingly to keep
00089    // the compiler happy, even with /Wp64.
00090    return (Type)(static_cast<LONG_PTR>(::SetWindowLongPtr(hWnd, n, (LONG)((LONG_PTR)(ptr)))));
00091 #else
00092    return (Type)(static_cast<LONG_PTR>(::SetWindowLongPtr(hWnd, n, (LONG_PTR)(ptr))));
00093 #endif
00094 }
00095 
00096 template<> inline bool DLSetWindowLongPtr(HWND hWnd, bool bo, int n)
00097 {
00098    // Specialize for bool so we can quietly deal 
00099    // warning C4800: 'LONG_PTR' : forcing value to bool 'true' or 'false' (performance warning)
00100    return ::SetWindowLongPtr(hWnd, n, bo) != 0;
00101 }
00102 
00103 inline WNDPROC DLSetWindowLongPtr(HWND hWnd, WNDPROC pfn)
00104 {
00105    return DLSetWindowLongPtr<WNDPROC>(hWnd, pfn, GWLP_WNDPROC);
00106 }
00107 
00108 inline WNDPROC DLSetWindowProc(HWND hWnd, WNDPROC pfn)
00109 {
00110    return DLSetWindowLongPtr<WNDPROC>(hWnd, pfn, GWLP_WNDPROC);
00111 }
00112 
00113 #if !defined( _WIN64 )
00114 typedef INT_PTR (CALLBACK* DL_NOTQUITE_WNDPROC)(HWND, UINT, WPARAM, LPARAM);
00115 #endif
00116 
00117 /*
00118    same as above, but for class instead of HWND.
00119 */
00120 
00121 template<typename DataPtr> DataPtr DLGetClassLongPtr(HWND hWnd, int n, DataPtr = NULL)
00122 {
00123    return (DataPtr)(static_cast<LONG_PTR>(::GetClassLongPtr(hWnd, n)));
00124 }
00125 
00126 template<typename DataPtr> DataPtr DLGetClassLongPtr(HWND hWnd, DataPtr* pPtr, int n)
00127 {
00128    *pPtr = DLGetClassLongPtr<DataPtr>(hWnd, n);
00129 
00130    return *pPtr;
00131 }
00132 
00133 template<> inline bool DLGetClassLongPtr(HWND hWnd, int n, bool)
00134 {
00135    return ::GetClassLongPtr(hWnd, n) != 0;
00136 }
00137 
00138 inline WNDPROC DLGetClassWindowProc(HWND hWnd)
00139 {
00140    return DLGetClassLongPtr<WNDPROC>(hWnd, GCLP_WNDPROC);
00141 }
00142 
00143 template<typename Type> inline Type DLSetClassLongPtr(HWND hWnd, Type ptr, int n)
00144 {
00145 #if !defined( _WIN64 )
00146    // SetClassLongPtr() maps to SetClassLong() in 32 bit land; react accordingly to keep
00147    // the compiler happy, even with /Wp64.
00148    return (Type)(static_cast<LONG_PTR>(::SetClassLongPtr(hWnd, n, (LONG)((LONG_PTR)(ptr)))));
00149 #else
00150    return (Type)(static_cast<LONG_PTR>(::SetClassLongPtr(hWnd, n, (LONG_PTR)(ptr))));
00151 #endif
00152 }
00153 
00154 template<> inline bool DLSetClassLongPtr(HWND hWnd, bool bo, int n)
00155 {
00156    // Specialize for bool so we can quietly deal 
00157    // warning C4800: 'LONG_PTR' : forcing value to bool 'true' or 'false' (performance warning)
00158    return ::SetClassLongPtr(hWnd, n, bo) != 0;
00159 }
00160 
00161 /*
00162    RegSet/GetValueEx() does not handle buffers larger than 4G, even in Win64.  Not
00163    really an issue since who would want to store this much data in the registry
00164    anyway.
00165 
00166    Unfortunately we often use it to get/set strings, and the length is often obtained
00167    from _tcslen(), which returns a size_t and would therefore require casting, not
00168    to mention that the registry functions deal in _bytes_, not _chars_ so this has
00169    to be taken into account as well.
00170 
00171    These helper functions shield you from the nitty-gritty of casts, and reduce
00172    the number of parameters you have to use.  Again, no runtime hit because it's all
00173    inlined.
00174 
00175    This method of having explicit function names instead of one DLRegSetValueEx() 
00176    overloaded for every data type we awnt was prefered to prevent automatic typecasting
00177    occuring behind your back.
00178 
00179    Instead of (which, by the way, is off by one byte when compiled for UNICODE, but 
00180    this was lifted from the codebase and is another reason why using our replacement 
00181    functions is a Good Thing):
00182 
00183    RegSetValueEx(key2, NULL, 0, REG_SZ, (LPBYTE)buf, _tcslen(buf)*sizeof(MCHAR)+1);
00184 
00185    you should instead do:
00186 
00187    DLRegSetString(key2, buf);
00188 */
00189 
00190 UtilExport LONG DLRegSetString(HKEY key, const MCHAR* lpValue, const MCHAR* lpValueName = NULL);
00191 UtilExport LONG DLRegSetDWord(HKEY key, DWORD dw, const MCHAR* lpValueName = NULL);
00192 
00193 template <typename BlobType> inline LONG DLRegSetBlob(HKEY key, const BlobType* lpbValue, DWORD n, 
00194                          LPCMSTR lpValueName = NULL)
00195 {
00196    return ::RegSetValueEx(key, lpValueName, 0, REG_BINARY, 
00197                           reinterpret_cast<LPBYTE>(const_cast<BlobType*>(lpbValue)), 
00198                           n * sizeof(BlobType));
00199 }
00200 
00201 /*
00202    GetTextExtentPoint32 works with strings up to 2G, even in Win64.  Not a problem,
00203    but since the length is often obtained from _tcslen(), a lot of casting ensues.
00204 */
00205 UtilExport BOOL DLGetTextExtent(HDC hDC, const MCHAR* text, LPSIZE lpExtent);
00206 UtilExport BOOL DLGetTextExtent(HDC hDC, const MCHAR* text, size_t len, LPSIZE lpExtent);
00207 
00208 /*
00209    Same with TextOut, TabbedTextOut, DrawText
00210 */
00211 UtilExport BOOL DLTextOut(HDC hDC, int x, int y, const MCHAR* text);
00212 UtilExport BOOL DLTextOut(HDC hDC, int x, int y, const MCHAR* text, size_t len);
00213 UtilExport LONG DLTabbedTextOut(HDC hDC, int x, int y, const MCHAR* text, int nTabs, 
00214                             const INT* pTabPositions, int nTabOrigin);
00215 
00216 UtilExport int DLDrawText(HDC hDC, MCHAR* lpString, LPRECT lpRect, UINT uFormat);
00217 UtilExport int DLDrawText(HDC hDC, MCHAR* lpString, size_t len, LPRECT lpRect, UINT uFormat);
00218 
00219 /*
00220    Extract hi/low part of pointer-sized chunks, unlike LOWORD/HIWORD which always return
00221    WORD-sized chunks.
00222 
00223    Notice that the return value changes depending on your platform.
00224 */
00225 
00226 #if defined( _WIN64 )
00227 
00228 inline DWORD PointerHiPart(LONG_PTR ptr)
00229 {
00230    return static_cast<DWORD>((ptr >> 32) & 0xffffffff);
00231 }
00232 
00233 inline DWORD PointerLoPart(LONG_PTR ptr)
00234 {
00235    return static_cast<DWORD>(ptr & 0xffffffff);
00236 }
00237 
00238 inline DWORD PointerHiPart(ULONG_PTR ptr)
00239 {
00240    return static_cast<DWORD>(ptr >> 32);
00241 }
00242 
00243 inline DWORD PointerLoPart(ULONG_PTR ptr)
00244 {
00245    return static_cast<DWORD>(ptr);
00246 }
00247 
00248 inline DWORD PointerHiPart(void* ptr)
00249 {
00250    return PointerHiPart(reinterpret_cast<ULONG_PTR>(ptr));
00251 }
00252 
00253 inline DWORD PointerLoPart(void* ptr)
00254 {
00255    return PointerLoPart(reinterpret_cast<ULONG_PTR>(ptr));
00256 }
00257 
00258 #else
00259 
00260 inline WORD PointerHiPart(ULONG_PTR ptr)
00261 {
00262    return static_cast<WORD>(ptr >> 16);
00263 }
00264 
00265 inline WORD PointerLoPart(ULONG_PTR ptr)
00266 {
00267    return static_cast<WORD>(ptr);
00268 }
00269 
00270 inline WORD PointerHiPart(LONG_PTR ptr)
00271 {
00272    return static_cast<WORD>((ptr >> 16) & 0xffff);
00273 }
00274 
00275 inline WORD PointerLoPart(LONG_PTR ptr)
00276 {
00277    return static_cast<WORD>(ptr & 0xffff);
00278 }
00279 
00280 inline WORD PointerHiPart(void* ptr)
00281 {
00282    return PointerHiPart(reinterpret_cast<ULONG_PTR>(ptr));
00283 }
00284 
00285 inline WORD PointerLoPart(void* ptr)
00286 {
00287    return PointerLoPart(reinterpret_cast<ULONG_PTR>(ptr));
00288 }
00289 
00290 #endif
00291 
00292 /*
00293    Fowler/Noll/Vo hashing algorithm, taken from http://www.isthe.com/chongo/tech/comp/fnv/.
00294 
00295    We hash to 32 bits values, even for 64 bit pointers, since it would make little sense
00296    to have such a huge hash table...
00297 
00298  From http://www.isthe.com/chongo/src/fnv/hash_32.c:
00299 
00300  ***
00301  *
00302  * Fowler/Noll/Vo hash
00303  *
00304  * The basis of this hash algorithm was taken from an idea sent
00305  * as reviewer comments to the IEEE POSIX P1003.2 committee by:
00306  *
00307  *      Phong Vo (http://www.research.att.com/info/kpv/)
00308  *      Glenn Fowler (http://www.research.att.com/~gsf/)
00309  *
00310  * In a subsequent ballot round:
00311  *
00312  *      Landon Curt Noll (http://www.isthe.com/chongo/)
00313  *
00314  * improved on their algorithm.  Some people tried this hash
00315  * and found that it worked rather well.  In an EMail message
00316  * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash.
00317  *
00318  * FNV hashes are designed to be fast while maintaining a low
00319  * collision rate. The FNV speed allows one to quickly hash lots
00320  * of data while maintaining a reasonable collision rate.  See:
00321  *
00322  *      http://www.isthe.com/chongo/tech/comp/fnv/index.html
00323  *
00324  * for more details as well as other forms of the FNV hash.
00325  ***
00326  *
00327  * NOTE: The FNV-0 historic hash is not recommended.  One should use
00328  *  the FNV-1 hash instead.
00329  *
00330  * To use the 32 bit FNV-0 historic hash, pass FNV0_32_INIT as the
00331  * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str().
00332  *
00333  * To use the recommended 32 bit FNV-1 hash, pass FNV1_32_INIT as the
00334  * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str().
00335  *
00336  ***
00337  *
00338  * Please do not copyright this code.  This code is in the public domain.
00339    
00340 */
00341 
00342 enum
00343 {
00344    FNV1_32_INIT = 0x811c9dc5,
00345    FNV_32_PRIME = 0x01000193
00346 };
00347 
00348 
00349 /*
00350  * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer
00351  *
00352  * input:
00353  * buf   - start of buffer to hash
00354  * len   - length of buffer in octets
00355  * hval  - previous hash value or 0 if first call
00356  *
00357  * returns:
00358  * 32 bit hash as a static hash type
00359  *
00360  * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hval
00361  *  argument on the first call to either fnv_32_buf() or fnv_32_str().
00362  *
00363  * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval
00364  *  argument on the first call to either fnv_32_buf() or fnv_32_str().
00365  */
00366 inline unsigned int fnv_32_buf(const void *buf, int len, unsigned int hval)
00367 {
00368    const unsigned char *bp = (const unsigned char *)buf; /* start of buffer */
00369    const unsigned char *be = bp + len;                   /* beyond end of buffer */
00370 
00371    /*
00372     * FNV-1 hash each octet in the buffer
00373     */
00374    while (bp < be) 
00375    {
00376       /* multiply by the 32 bit FNV magic prime mod 2^32 */
00377       hval *= FNV_32_PRIME;
00378 
00379       /* xor the bottom with the current octet */
00380       hval ^= (unsigned int)*bp++;
00381    }
00382 
00383    /* return our new hash value */
00384    return hval;
00385 }
00386 
00387 
00388 template <typename T> inline unsigned int DLObjectHash(T& t, int HashTableSize = 0)
00389 {
00390    // Since we're always hashing single objects, we hash using the 'init value';
00391    // we'd have to carry it over if we were hashing all fields in a structure, for
00392    // instance.
00393    // You should never never never never attempt to hash a structure by passing its
00394    // pointer, since you'd end up hashing the padding bytes as well, which are definitely
00395    // not going to be preserved.
00396    unsigned int hash = fnv_32_buf(&t, sizeof(t), (unsigned int)FNV1_32_INIT);
00397 
00398    return HashTableSize ? hash % HashTableSize : hash;
00399 }
00400 
00401 inline unsigned int DLPointerHash(const void* pv, int HashTableSize = 0)
00402 {
00403    return DLObjectHash(pv, HashTableSize);
00404 }
00405 
00406 /*
00407    abs() when you're using _PTR values; in Win64, abs() will complain -- you should be
00408    using abs64.
00409 
00410    Also, with 2005 fabs(int) generates a warning.
00411 */
00412 
00413 inline int DL_abs(int n) { return std::abs(n); }
00414 inline __int64 DL_abs(__int64 n) { return (n < 0) ? -n : n; }
00415 
00416 inline float DL_abs(float f)     { return std::fabsf(f); }
00417 inline double DL_abs(double f)   { return std::fabs(f); }
00418 inline long double DL_abs(long double f) { return std::fabsl(f); }
00419 
00420 /*
00421    hash_set / hash_map changed namespace with VS 2005
00422 */
00423 #define DL_STDEXT        stdext
00424 
00425 #define DL_NON_RTTI_OBJECT  std::__non_rtti_object
00426 
00427 
00428 // With newer, C++-compliant versions, you need to specify that a type is a typename
00429 // in situations such as: template <typename T> void foo(typename T::SomeType);
00430 #ifndef DL_TYPENAME_OUTSIDE_TEMPLATE
00431     #define DL_TYPENAME_OUTSIDE_TEMPLATE  typename
00432 #endif
00433