594 lines
18 KiB
C++
594 lines
18 KiB
C++
/********************************************************************
|
|
|
|
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
|