/******************************************************************** Copyright (c) 1999-2000 Microsoft Corporation Module Name: pfrutil.h Abstract: PFR utility stuff Revision History: DerekM created 05/01/99 ********************************************************************/ #ifndef PFRUTIL_H #define PFRUTIL_H // this turns on the manifest mode heap collection #define MANIFEST_HEAP // make sure both _DEBUG & DEBUG are defined if one is defined. Otherwise // the ASSERT macro never does anything #if defined(_DEBUG) && !defined(DEBUG) #define DEBUG 1 #endif #if defined(DEBUG) && !defined(_DEBUG) #define _DEBUG 1 #endif #include "dbgtrace.h" //////////////////////////////////////////////////////////////////////////// // tracing wrappers // can't call HRESULT_FROM_WIN32 with a fn as a parameter cuz it is a macro // and evaluates the expression 3 times. This is a particularlly bad thing // when u don't look at macros first to see what they do. inline HRESULT ChangeErrToHR(DWORD dwErr) { return HRESULT_FROM_WIN32(dwErr); } #if defined(NOTRACE) #define INIT_TRACING #define TERM_TRACING #define USE_TRACING(sz) #define DBG_MSG(sz) #define TESTHR(hr, fn) \ hr = (fn); #define TESTBOOL(hr, fn) \ hr = ((fn) ? NOERROR : HRESULT_FROM_WIN32(GetLastError())); #define TESTERR(hr, fn) \ SetLastError((fn)); \ hr = HRESULT_FROM_WIN32(GetLastError()); #define VALIDATEPARM(hr, expr) \ hr = ((expr) ? E_INVALIDARG : NOERROR); #define VALIDATEEXPR(hr, expr, hrErr) \ hr = ((expr) ? (hrErr) : NOERROR); #else #define INIT_TRACING \ InitAsyncTrace(); #define TERM_TRACING \ TermAsyncTrace(); #define USE_TRACING(sz) \ TraceQuietEnter(sz); \ TraceFunctEntry(sz); \ DWORD __dwtraceGLE = GetLastError(); \ #define DBG_MSG(sz) \ ErrorTrace(0, sz) #define TESTHR(hr, fn) \ if (FAILED(hr = (fn))) \ { \ __dwtraceGLE = GetLastError(); \ ErrorTrace(0, "%s failed. Err: 0x%08x", #fn, hr); \ SetLastError(__dwtraceGLE); \ } \ #define TESTBOOL(hr, fn) \ hr = NOERROR; \ if ((fn) == FALSE) \ { \ __dwtraceGLE = GetLastError(); \ hr = HRESULT_FROM_WIN32(__dwtraceGLE); \ ErrorTrace(0, "%s failed. Err: 0x%08x", #fn, __dwtraceGLE); \ SetLastError(__dwtraceGLE); \ } #define TESTERR(hr, fn) \ SetLastError((fn)); \ if (FAILED(hr = HRESULT_FROM_WIN32(GetLastError()))) \ { \ __dwtraceGLE = GetLastError(); \ ErrorTrace(0, "%s failed. Err: %d", #fn, __dwtraceGLE); \ SetLastError(__dwtraceGLE); \ } #define VALIDATEPARM(hr, expr) \ if (expr) \ { \ ErrorTrace(0, "Invalid parameters passed to %s", \ ___pszFunctionName); \ SetLastError(ERROR_INVALID_PARAMETER); \ hr = E_INVALIDARG; \ } \ else hr = NOERROR; #define VALIDATEEXPR(hr, expr, hrErr) \ if (expr) \ { \ ErrorTrace(0, "Expression failure %s", #expr); \ hr = (hrErr); \ } \ else hr = NOERROR; #endif //////////////////////////////////////////////////////////////////////////// // Memory #if defined(DEBUG) || defined(_DEBUG) // this structure must ALWAYS be 8 byte aligned. Add padding to the end if // it isn't. struct SMyMemDebug { __int64 hHeap; __int64 cb; DWORD dwTag; DWORD dwChk; }; #endif extern HANDLE g_hPFPrivateHeap; // ************************************************************************** inline HANDLE MyHeapCreate(SIZE_T cbInitial = 8192, SIZE_T cbMax = 0) { return HeapCreate(0, cbInitial, cbMax); } // ************************************************************************** inline BOOL MyHeapDestroy(HANDLE hHeap) { return HeapDestroy(hHeap); } // ************************************************************************** inline LPVOID MyAlloc(SIZE_T cb, HANDLE hHeap = NULL, BOOL fZero = TRUE) { #if defined(DEBUG) || defined(_DEBUG) SMyMemDebug *psmmd; LPBYTE pb; cb += (sizeof(SMyMemDebug) + 4); hHeap = (hHeap != NULL) ? hHeap : GetProcessHeap(); pb = (LPBYTE)HeapAlloc(hHeap, ((fZero) ? HEAP_ZERO_MEMORY : 0), cb); if (pb != NULL) { psmmd = (SMyMemDebug *)pb; psmmd->hHeap = (__int64)hHeap; psmmd->cb = (__int64)cb; psmmd->dwTag = 0xBCBCBCBC; psmmd->dwChk = 0xBCBCBCBC; // do this cuz it's easier than figuring out the alignment and // manually converting it to a 4 byte aligned value *(pb + cb - 4) = 0xBC; *(pb + cb - 3) = 0xBC; *(pb + cb - 2) = 0xBC; *(pb + cb - 1) = 0xBC; pb = (PBYTE)pb + sizeof(SMyMemDebug); } return pb; #else return HeapAlloc(((hHeap != NULL) ? hHeap : GetProcessHeap()), ((fZero) ? HEAP_ZERO_MEMORY : 0), cb); #endif } // ************************************************************************** inline LPVOID MyReAlloc(LPVOID pv, SIZE_T cb, HANDLE hHeap = NULL, BOOL fZero = TRUE) { #if defined(DEBUG) || defined(_DEBUG) SMyMemDebug *psmmd; SIZE_T cbOld; LPBYTE pbNew; LPBYTE pb = (LPBYTE)pv; // if this is NULL, force a call to HeapReAlloc so that it can set the // proper error for GLE to fetch if (pv == NULL) { SetLastError(0); return NULL; } pb -= sizeof(SMyMemDebug); hHeap = (hHeap != NULL) ? hHeap : GetProcessHeap(); // wrap this in a try block in case the memory was not allocated // by us or is corrupted- in which case the following could // cause an AV. __try { psmmd = (SMyMemDebug *)pb; cbOld = (SIZE_T)psmmd->cb; _ASSERT(psmmd->hHeap == (__int64)hHeap); _ASSERT(psmmd->dwTag == 0xBCBCBCBC); _ASSERT(psmmd->dwChk == 0xBCBCBCBC); // do this cuz it's easier than figuring out the alignment and // manually converting it to a 4 byte aligned value _ASSERT(*(pb + cbOld - 4) == 0xBC); _ASSERT(*(pb + cbOld - 3) == 0xBC); _ASSERT(*(pb + cbOld - 2) == 0xBC); _ASSERT(*(pb + cbOld - 1) == 0xBC); if (psmmd->hHeap != (__int64)hHeap) hHeap = (HANDLE)(DWORD_PTR)psmmd->hHeap; } __except(EXCEPTION_EXECUTE_HANDLER) { _ASSERT(FALSE); } hHeap = *((HANDLE *)pb); cb += (sizeof(SMyMemDebug) + 4); pbNew = (LPBYTE)HeapReAlloc(hHeap, ((fZero) ? HEAP_ZERO_MEMORY : 0), pb, cb); if (pbNew != NULL) { psmmd = (SMyMemDebug *)pb; psmmd->hHeap = (__int64)hHeap; psmmd->cb = (__int64)cb; psmmd->dwTag = 0xBCBCBCBC; psmmd->dwChk = 0xBCBCBCBC; // do this cuz it's easier than figuring out the alignment and // manually converting it to a 4 byte aligned value *(pb + cb - 4) = 0xBC; *(pb + cb - 3) = 0xBC; *(pb + cb - 2) = 0xBC; *(pb + cb - 1) = 0xBC; pb = (PBYTE)pb + sizeof(SMyMemDebug); } return pv; #else return HeapReAlloc(((hHeap != NULL) ? hHeap : GetProcessHeap()), ((fZero) ? HEAP_ZERO_MEMORY : 0), pv, cb); #endif } // ************************************************************************** inline BOOL MyFree(LPVOID pv, HANDLE hHeap = NULL) { #if defined(DEBUG) || defined(_DEBUG) SMyMemDebug *psmmd; SIZE_T cbOld; HANDLE hAllocHeap; LPBYTE pb = (LPBYTE)pv; // if this is NULL, force a call to HeapFree so that it can set the // proper error for GLE to fetch if (pv == NULL) return TRUE; pb -= sizeof(SMyMemDebug); hHeap = (hHeap != NULL) ? hHeap : GetProcessHeap(); // wrap this in a try block in case the memory was not allocated // by us or is corrupted- in which case the following could // cause an AV. __try { psmmd = (SMyMemDebug *)pb; cbOld = (SIZE_T)psmmd->cb; _ASSERT(psmmd->hHeap == (__int64)hHeap); _ASSERT(psmmd->dwTag == 0xBCBCBCBC); _ASSERT(psmmd->dwChk == 0xBCBCBCBC); // do this cuz it's easier than figuring out the alignment and // manually converting it to a 4 byte aligned value _ASSERT(*(pb + cbOld - 4) == 0xBC); _ASSERT(*(pb + cbOld - 3) == 0xBC); _ASSERT(*(pb + cbOld - 2) == 0xBC); _ASSERT(*(pb + cbOld - 1) == 0xBC); if (psmmd->hHeap != (__int64)hHeap) hHeap = (HANDLE)(DWORD_PTR)psmmd->hHeap; } __except(EXCEPTION_EXECUTE_HANDLER) { _ASSERT(FALSE); } FillMemory(pb, cbOld, 0xCB); return HeapFree(hHeap, 0, pb); #else return HeapFree(((hHeap != NULL) ? hHeap : GetProcessHeap()), 0, pv); #endif } //////////////////////////////////////////////////////////////////////////// // useful inlines / defines // ************************************************************************** inline DWORD MyMax(DWORD a, DWORD b) { return (a > b) ? a : b; } // ************************************************************************** inline DWORD MyMin(DWORD a, DWORD b) { return (a <= b) ? a : b; } #define Err2HR(dwErr) HRESULT_FROM_WIN32(dwErr) #define sizeofSTRW(wsz) sizeof(wsz) / sizeof(WCHAR) //////////////////////////////////////////////////////////////////////////// // Files const WCHAR c_wszDirSuffix[] = L".dir00"; HRESULT OpenFileMapped(LPWSTR wszFile, LPVOID *ppvFile, DWORD *pcbFile); HRESULT DeleteTempFile(LPWSTR wszFile); HRESULT MyCallNamedPipe(LPCWSTR wszPipe, LPVOID pvIn, DWORD cbIn, LPVOID pvOut, DWORD cbOut, DWORD *pcbRead, DWORD dwWaitPipe, DWORD dwWaitRead = INFINITE); DWORD CreateTempDirAndFile(LPCWSTR wszTempDir, LPCWSTR wszName, LPWSTR *pwszPath); BOOL DeleteTempDirAndFile(LPCWSTR wszPath, BOOL fFilePresent); #ifdef MANIFEST_HEAP BOOL DeleteFullAndTriageMiniDumps(LPCWSTR wszPath); #endif // MANIFEST_HEAP //////////////////////////////////////////////////////////////////////////// // Security BOOL AllocSD(SECURITY_DESCRIPTOR *psd, DWORD dwOLs, DWORD dwAd, DWORD dwWA); void FreeSD(SECURITY_DESCRIPTOR *psd); BOOL IsUserAnAdmin(HANDLE hToken); //////////////////////////////////////////////////////////////////////////// // Registry enum EPFORK { orkWantWrite = 0x1, orkUseWOW64 = 0x2, }; HRESULT OpenRegKey(HKEY hkeyMain, LPCWSTR wszSubKey, DWORD dwOpt, HKEY *phkey); HRESULT ReadRegEntry(HKEY hkey, LPCWSTR szValName, DWORD *pdwType, PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault, DWORD cbDefault); HRESULT ReadRegEntry(HKEY *rghkey, DWORD cKeys, LPCWSTR wszValName, DWORD *pdwType, PBYTE pbBuffer, DWORD *pcbBuffer, PBYTE pbDefault, DWORD cbDefault, DWORD *piKey = NULL); //////////////////////////////////////////////////////////////////////////// // version info #define APP_WINCOMP 0x1 #define APP_MSAPP 0x2 DWORD IsMicrosoftApp(LPWSTR wszAppPath, PBYTE pbAppInfo, DWORD cbAppInfo); //////////////////////////////////////////////////////////////////////////// // String WCHAR *MyStrStrIW(const WCHAR *wcs1, const WCHAR *wcs2); CHAR *MyStrStrIA(const CHAR *cs1, const CHAR *cs2); HRESULT MyURLEncode(LPWSTR wszDest, DWORD cchDest, LPWSTR wszSrc); //////////////////////////////////////////////////////////////////////////// // CPFGenericClassBase class CPFGenericClassBase { public: // CPFGenericClassBase(void) {} // virtual ~CPFGenericClassBase(void) {} void *operator new(size_t size) { return MyAlloc(size, NULL, FALSE); } void operator delete(void *pvMem) { if (pvMem != NULL) MyFree(pvMem, NULL); } }; class CPFPrivHeapGenericClassBase { public: // CPFGenericClassBase(void) {} // virtual ~CPFGenericClassBase(void) {} void *operator new(size_t size) { return MyAlloc(size, g_hPFPrivateHeap, FALSE); } void operator delete(void *pvMem) { if (pvMem != NULL) MyFree(pvMem, g_hPFPrivateHeap); } }; //////////////////////////////////////////////////////////////////////////// // CAutoUnlockCS // This class wrappers a critical section. It will automatically unlock the // CS when the class destructs (assuming it is locked) // NOTE: this object is intended to be used only as a local variable of a // function, not as a global variable or class member. class CAutoUnlockCS { private: #if defined(DEBUG) || defined(_DEBUG) DWORD m_dwOwningThread; #endif CRITICAL_SECTION *m_pcs; DWORD m_cLocks; public: CAutoUnlockCS(CRITICAL_SECTION *pcs, BOOL fTakeLock = FALSE) { m_pcs = pcs; m_cLocks = 0; #if defined(DEBUG) || defined(_DEBUG) m_dwOwningThread = 0; #endif if (fTakeLock) this->Lock(); } ~CAutoUnlockCS(void) { _ASSERT(m_cLocks <= 1); if (m_pcs != NULL) { #if defined(DEBUG) || defined(_DEBUG) if (m_cLocks > 0) _ASSERT(m_dwOwningThread == GetCurrentThreadId()); #endif while(m_cLocks > 0) { LeaveCriticalSection(m_pcs); m_cLocks--; } } } void Lock(void) { if (m_pcs != NULL) { EnterCriticalSection(m_pcs); m_cLocks++; #if defined(DEBUG) || defined(_DEBUG) m_dwOwningThread = GetCurrentThreadId(); #endif } } void Unlock(void) { _ASSERT(m_cLocks > 0); _ASSERT(m_dwOwningThread == GetCurrentThreadId()); if (m_pcs != NULL && m_cLocks > 0) { m_cLocks--; LeaveCriticalSection(m_pcs); } #if defined(DEBUG) || defined(_DEBUG) if (m_cLocks == 0) m_dwOwningThread = 0; #endif } }; //////////////////////////////////////////////////////////////////////////// // CAutoUnlockMutex // This class wrappers a mutex. It will automatically unlock the // mutex when the class destructs (assuming it is owned) // NOTE: this object is intended to be used only as a local variable of a // function, not as a global variable or class member. class CAutoUnlockMutex { private: #if defined(DEBUG) || defined(_DEBUG) DWORD m_dwOwningThread; #endif HANDLE m_hmut; DWORD m_cLocks; public: CAutoUnlockMutex(HANDLE hmut, BOOL fTakeLock = FALSE) { m_hmut = hmut; m_cLocks = 0; #if defined(DEBUG) || defined(_DEBUG) m_dwOwningThread = 0; #endif if (fTakeLock) this->Lock(); } ~CAutoUnlockMutex(void) { _ASSERT(m_cLocks <= 1); if (m_hmut != NULL) { #if defined(DEBUG) || defined(_DEBUG) if (m_cLocks > 0) _ASSERT(m_dwOwningThread == GetCurrentThreadId()); #endif while(m_cLocks > 0) { ReleaseMutex(m_hmut); m_cLocks--; } } } BOOL Lock(DWORD dwTimeout = INFINITE) { if (m_hmut != NULL) { if (WaitForSingleObject(m_hmut, dwTimeout) != WAIT_OBJECT_0) return FALSE; m_cLocks++; #if defined(DEBUG) || defined(_DEBUG) m_dwOwningThread = GetCurrentThreadId(); #endif } return TRUE; } void Unlock(void) { _ASSERT(m_cLocks > 0); _ASSERT(m_dwOwningThread == GetCurrentThreadId()); if (m_hmut != NULL && m_cLocks > 0) { m_cLocks--; ReleaseMutex(m_hmut); } } }; #endif