532 lines
14 KiB
C
532 lines
14 KiB
C
#ifndef _UTILW32_H
|
|
#define _UTILW32_H
|
|
|
|
|
|
// Redirect Asserts in inline code to seem to fire from this file
|
|
|
|
#define szAssertFilename __FILE__
|
|
|
|
|
|
#ifdef DEBUG
|
|
ERR ErrERRCheck( ERR err );
|
|
#else
|
|
#define ErrERRCheck( err ) ( err )
|
|
#endif
|
|
|
|
|
|
// Init / Term
|
|
|
|
ERR ErrUtilInit(void);
|
|
VOID UtilTerm(void);
|
|
|
|
|
|
// Miscellaneous
|
|
|
|
STATIC INLINE DWORD DwUtilGetLastError( void ) { return GetLastError(); }
|
|
|
|
STATIC INLINE ULONG UlUtilGetTickCount( VOID ) { return GetTickCount(); }
|
|
|
|
STATIC INLINE QWORD QwUtilPerfCount( VOID )
|
|
{
|
|
QWORDX qwx;
|
|
|
|
if ( !QueryPerformanceCounter( (LARGE_INTEGER *) &qwx.qw ) )
|
|
{
|
|
qwx.h = GetTickCount();
|
|
qwx.l = 0;
|
|
}
|
|
return qwx.qw;
|
|
}
|
|
|
|
STATIC INLINE QWORD QwUtilPerfCountFrq( VOID )
|
|
{
|
|
QWORDX qwx;
|
|
|
|
if ( !QueryPerformanceFrequency( (LARGE_INTEGER *) &qwx.qw ) )
|
|
{
|
|
qwx.h = 1000;
|
|
qwx.l = 0;
|
|
}
|
|
return qwx.qw;
|
|
}
|
|
|
|
STATIC INLINE double DblUtilPerfElapsedTime( QWORD qwStartCount )
|
|
{
|
|
return (signed __int64) ( QwUtilPerfCount() - qwStartCount )
|
|
/ (double) (signed __int64) QwUtilPerfCountFrq();
|
|
}
|
|
|
|
STATIC INLINE double DblUtilPerfElapsedTime2( QWORD qwStartCount, QWORD qwEndCount )
|
|
{
|
|
return (signed __int64) ( qwEndCount - qwStartCount )
|
|
/ (double) (signed __int64) QwUtilPerfCountFrq();
|
|
}
|
|
|
|
|
|
CHAR *GetDebugEnvValue( CHAR *szEnvVar );
|
|
|
|
ERR ErrUtilCloseHandle( HANDLE hf );
|
|
|
|
// for system information such as virtual page size and malloc granularity
|
|
extern SYSTEM_INFO siSystemConfig;
|
|
|
|
|
|
// Event Logging
|
|
|
|
typedef unsigned long MessageId;
|
|
#include "jetmsg.h"
|
|
|
|
extern int fNoWriteAssertEvent;
|
|
|
|
VOID UtilReportEvent( WORD fwEventType, WORD fwCategory, DWORD IDEvent, WORD cStrings, LPCTSTR *plpszStrings );
|
|
VOID UtilReportEventOfError( WORD fwCategory, DWORD IDEvent, ERR err );
|
|
|
|
|
|
// Registry Support
|
|
|
|
ERR ErrUtilRegInit(void);
|
|
ERR ErrUtilRegTerm(void);
|
|
ERR ErrUtilRegReadConfig(void);
|
|
|
|
extern HKEY hkeyHiveRoot;
|
|
|
|
ERR ErrUtilRegOpenKeyEx( HKEY hkeyRoot, LPCTSTR lpszSubKey, PHKEY phkResult );
|
|
ERR ErrUtilRegCloseKeyEx( HKEY hkey );
|
|
ERR ErrUtilRegCreateKeyEx( HKEY hkeyRoot,
|
|
LPCTSTR lpszSubKey,
|
|
PHKEY phkResult,
|
|
LPDWORD lpdwDisposition );
|
|
ERR ErrUtilRegDeleteKeyEx( HKEY hkeyRoot, LPCTSTR lpszSubKey );
|
|
ERR ErrUtilRegDeleteValueEx( HKEY hkey, LPTSTR lpszValue );
|
|
ERR ErrUtilRegSetValueEx( HKEY hkey,
|
|
LPCTSTR lpszValue,
|
|
DWORD fdwType,
|
|
CONST BYTE *lpbData,
|
|
DWORD cbData );
|
|
ERR ErrUtilRegQueryValueEx( HKEY hkey,
|
|
LPTSTR lpszValue,
|
|
LPDWORD lpdwType,
|
|
LPBYTE *lplpbData );
|
|
|
|
|
|
// DLL Support
|
|
|
|
STATIC INLINE BOOL FUtilLoadLibrary(const char *pszLibrary, ULONG_PTR *phmod)
|
|
{
|
|
HANDLE hmod;
|
|
|
|
hmod = LoadLibrary((LPTSTR) pszLibrary);
|
|
|
|
// restore original error mode
|
|
*phmod = (ULONG_PTR) hmod;
|
|
|
|
return(hmod != NULL);
|
|
}
|
|
|
|
STATIC INLINE PFN PfnUtilGetProcAddress(ULONG_PTR hmod, unsigned ordinal)
|
|
{
|
|
return((PFN) GetProcAddress((HANDLE) hmod, MAKEINTRESOURCE(ordinal)));
|
|
}
|
|
|
|
STATIC INLINE void UtilFreeLibrary( unsigned hmod ) { FreeLibrary( LongToHandle(hmod)); }
|
|
|
|
|
|
// Date and Time
|
|
|
|
void UtilGetDateTime(DATESERIAL *pdt);
|
|
void UtilGetDateTime2(_JET_DATETIME *pdt);
|
|
char *SzUtilSerialToDate(JET_DATESERIAL dt);
|
|
|
|
|
|
// File Operations
|
|
|
|
typedef OVERLAPPED OLP;
|
|
|
|
ERR ErrUtilCreateDirectory( char *szDirName );
|
|
ERR ErrUtilRemoveDirectory( char *szDirName );
|
|
|
|
ERR ErrUtilGetFileAttributes( CHAR *szFileName, BOOL *pfReadOnly );
|
|
ERR ErrUtilFindFirstFile( CHAR *szFind, HANDLE *phandleFind, CHAR *szFound );
|
|
ERR ErrUtilFindNextFile( HANDLE handleFind, CHAR *szFound );
|
|
VOID UtilFindClose( HANDLE handleFind );
|
|
BOOL FUtilFileExists( CHAR *szFilePathName );
|
|
|
|
ERR ErrUtilOpenFile( char *szFileName, HANDLE *phf, ULONG ulFileSize, BOOL fReadOnly, BOOL fOverlapped );
|
|
ERR ErrUtilOpenReadFile( char *szFileName, HANDLE *phf );
|
|
|
|
ERR ErrUtilDeleteFile( char *szFileName );
|
|
ERR ErrUtilNewSize( HANDLE hf, ULONG ulFileSize, ULONG ulFileSizeHigh, BOOL fOverlapped );
|
|
ERR ErrUtilMove( char *szFrom, char *szTo );
|
|
ERR ErrUtilCopy( char *szFrom, char *szTo, BOOL fFailIfExists );
|
|
|
|
ERR ErrUtilReadFile( HANDLE hf, VOID *pvBuf, UINT cbBuf, UINT *pcbRead );
|
|
ERR ErrUtilReadBlock( HANDLE hf, VOID *pvBuf, UINT cbBuf, UINT *pcbRead );
|
|
ERR ErrUtilReadBlockOverlapped( HANDLE hf, VOID *pvBuf, UINT cbBuf,
|
|
DWORD *pcbRead, OLP *polp );
|
|
ERR ErrUtilReadBlockEx( HANDLE hf, VOID *pvBuf, UINT cbBuf, OLP *polp, VOID *pfnCompletion);
|
|
ERR ErrUtilWriteBlock( HANDLE hf, VOID *pvBuf, UINT cbBuf, UINT *pcbWritten );
|
|
ERR ErrUtilWriteBlockOverlapped( HANDLE hf, VOID *pvBuf, UINT cbBuf,
|
|
DWORD *pcbWrite, OLP *polp );
|
|
ERR ErrUtilWriteBlockEx( HANDLE hf, VOID *pvBuf, UINT cbBuf, OLP *polp, VOID *pfnCompletion);
|
|
|
|
ERR ErrUtilGetOverlappedResult( HANDLE hf, OLP *polp, UINT *pcb,
|
|
BOOL fWait );
|
|
|
|
STATIC INLINE ERR ErrUtilCloseFile( HANDLE hf ) { return ErrUtilCloseHandle( hf ); }
|
|
|
|
ERR ErrUtilReadShadowedHeader( CHAR *szFileName, BYTE *pbHeader, INT cbHeader );
|
|
ERR ErrUtilWriteShadowedHeader( CHAR *szFileName, BYTE *pbHeader, INT cbHeader );
|
|
#define ulChecksumMagicNumber 0x89abcdef
|
|
ULONG UlUtilChecksum( const BYTE *pb, INT cb );
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// VOID UtilChgFilePtr( HANDLE hf, LONG lRel, LONG *plRelHigh, ULONG ulRef, ULONG *pul )
|
|
// =========================================================
|
|
//
|
|
// Changes file hf pointer to position lRef relative to position :
|
|
//
|
|
// wRef FILE_BEGIN file beginnging
|
|
//
|
|
//----------------------------------------------------------
|
|
STATIC INLINE VOID UtilChgFilePtr( HANDLE hf, LONG lRel, LONG *plRelHigh, ULONG ulRef, ULONG *pul )
|
|
{
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
*pul = SetFilePointer( (HANDLE)hf, lRel, plRelHigh, ulRef );
|
|
Assert( ulRef != FILE_BEGIN || *pul == (ULONG)lRel );
|
|
return;
|
|
}
|
|
|
|
STATIC INLINE ERR ErrUtilGetDiskFreeSpace( char *szRoot,
|
|
ULONG *pSecPerClust,
|
|
ULONG *pcbSec,
|
|
ULONG *pcFreeClust,
|
|
ULONG *pcTotClust )
|
|
{
|
|
if ( GetDiskFreeSpace( szRoot, pSecPerClust, pcbSec, pcFreeClust, pcTotClust ) )
|
|
return JET_errSuccess;
|
|
else
|
|
return ErrERRCheck( JET_errDiskIO );
|
|
}
|
|
|
|
|
|
VOID UtilDebugBreak();
|
|
|
|
// Physical Memory Allocation
|
|
|
|
#if defined( DEBUG ) || defined( RFS2 )
|
|
|
|
void *SAlloc( unsigned long );
|
|
void OSSFree( void * );
|
|
void *LAlloc( unsigned long, unsigned short );
|
|
void OSLFree( void * );
|
|
|
|
STATIC INLINE VOID SFree( void *pv ) { OSSFree( pv ); }
|
|
STATIC INLINE VOID LFree( void *pv ) { OSLFree( pv ); }
|
|
|
|
#else // !DEBUG && !RFS2
|
|
|
|
#include <stdlib.h>
|
|
|
|
STATIC INLINE VOID *SAlloc( ULONG cb ) { return GlobalAlloc( 0, cb ); }
|
|
STATIC INLINE VOID SFree( VOID *pv ) { GlobalFree( pv ); }
|
|
STATIC INLINE VOID *LAlloc( ULONG c, USHORT cb ) { return GlobalAlloc( 0, c * cb ); }
|
|
STATIC INLINE VOID LFree( VOID *pv ) { GlobalFree( pv ); }
|
|
|
|
#endif // DEBUG || RFS2
|
|
|
|
|
|
// Virtual Memory Allocation
|
|
|
|
#if defined( DEBUG ) || defined( RFS2 )
|
|
|
|
VOID *PvUtilAlloc( ULONG dwSize );
|
|
VOID *PvUtilCommit( VOID *pv, ULONG dwSize );
|
|
VOID UtilFree( VOID *pv );
|
|
VOID UtilDecommit( VOID *pv, ULONG dwSize );
|
|
|
|
#else // !DEBUG && !RFS2
|
|
|
|
STATIC INLINE VOID *PvUtilAlloc( ULONG dwSize )
|
|
{
|
|
return VirtualAlloc( NULL, dwSize, MEM_RESERVE, PAGE_READWRITE );
|
|
}
|
|
|
|
STATIC INLINE VOID *PvUtilCommit( VOID *pv, ULONG ulSize )
|
|
{
|
|
return VirtualAlloc( pv, ulSize, MEM_COMMIT, PAGE_READWRITE );
|
|
}
|
|
|
|
STATIC INLINE VOID UtilFree( VOID *pv ) { VirtualFree( pv, 0, MEM_RELEASE ); }
|
|
|
|
STATIC INLINE VOID UtilDecommit( VOID *pv, ULONG dwSize ) { VirtualFree( pv, dwSize, MEM_DECOMMIT ); }
|
|
|
|
#endif // DEBUG || RFS2
|
|
|
|
VOID *PvUtilAllocAndCommit( ULONG dwSize );
|
|
|
|
|
|
// Critical Sections
|
|
|
|
#ifdef SPIN_LOCK
|
|
void UtilEnterNestableCriticalSection(void *pv);
|
|
void UtilLeaveNestableCriticalSection(void *pv);
|
|
void UtilEnterCriticalSection(void *pv);
|
|
void UtilLeaveCriticalSection(void *pv);
|
|
ERR ErrUtilInitializeCriticalSection(void **ppv);
|
|
void UtilDeleteCriticalSection(void *pv);
|
|
#else // !SPIN_LOCK
|
|
#ifdef DEBUG
|
|
void UtilEnterNestableCriticalSection(void *pv);
|
|
void UtilLeaveNestableCriticalSection(void *pv);
|
|
void UtilEnterCriticalSection(void *pv);
|
|
void UtilLeaveCriticalSection(void *pv);
|
|
ERR ErrUtilInitializeCriticalSection(void **ppv);
|
|
void UtilDeleteCriticalSection(void *pv);
|
|
#else // !DEBUG
|
|
STATIC INLINE ERR ErrUtilInitializeCriticalSection(void **ppv)
|
|
{
|
|
if ( !( *ppv = SAlloc( sizeof( CRITICAL_SECTION ) ) ) )
|
|
return ErrERRCheck( JET_errOutOfMemory );
|
|
InitializeCriticalSection( (LPCRITICAL_SECTION) *ppv );
|
|
return JET_errSuccess;
|
|
}
|
|
|
|
STATIC INLINE VOID UtilDeleteCriticalSection(void *pv)
|
|
{
|
|
DeleteCriticalSection( (LPCRITICAL_SECTION) pv );
|
|
SFree( pv );
|
|
}
|
|
|
|
STATIC INLINE VOID UtilEnterCriticalSection(void *pv)
|
|
{
|
|
EnterCriticalSection( (LPCRITICAL_SECTION) pv );
|
|
}
|
|
|
|
STATIC INLINE VOID UtilLeaveCriticalSection(void *pv)
|
|
{
|
|
LeaveCriticalSection( (LPCRITICAL_SECTION) pv );
|
|
}
|
|
|
|
STATIC INLINE VOID UtilEnterNestableCriticalSection( void *pv ) { UtilEnterCriticalSection( pv ); }
|
|
STATIC INLINE VOID UtilLeaveNestableCriticalSection( void *pv ) { UtilLeaveCriticalSection( pv ); }
|
|
#endif // !DEBUG
|
|
#endif // !SPIN_LOCK
|
|
|
|
#ifdef RETAIL
|
|
#define UtilAssertCrit( pv ) 0
|
|
#define UtilAssertNotInCrit( pv ) 0
|
|
#define UtilHoldCriticalSection( pv ) 0
|
|
#define UtilReleaseCriticalSection( pv ) 0
|
|
#else // !RETAIL
|
|
void UtilAssertCrit(void *pv);
|
|
void UtilAssertNotInCrit(void *pv);
|
|
void UtilHoldCriticalSection(void *pv);
|
|
void UtilReleaseCriticalSection(void *pv);
|
|
#endif // !RETAIL
|
|
|
|
|
|
// Signals
|
|
|
|
typedef HANDLE SIG;
|
|
|
|
#define sigNil ( (SIG) 0 )
|
|
|
|
STATIC INLINE ERR ErrUtilSignalCreate( void **ppv, const char *szSig )
|
|
{
|
|
*((SIG *) ppv) = CreateEvent( NULL, fTrue, fFalse, szSig );
|
|
return ( *ppv == sigNil ) ? ErrERRCheck( JET_errOutOfMemory ) : JET_errSuccess;
|
|
}
|
|
|
|
STATIC INLINE ERR ErrUtilSignalCreateAutoReset( void **ppv, const char *szSig )
|
|
{
|
|
*((SIG *) ppv) = CreateEvent( NULL, fFalse, fFalse, szSig );
|
|
return ( *ppv == sigNil ) ? ErrERRCheck( JET_errOutOfMemory ) : JET_errSuccess;
|
|
}
|
|
|
|
STATIC INLINE void UtilSignalReset( void *pv )
|
|
{
|
|
BOOL rc;
|
|
rc = ResetEvent( (SIG) pv );
|
|
Assert( rc != FALSE );
|
|
}
|
|
|
|
STATIC INLINE void UtilSignalSend( void *pv )
|
|
{
|
|
BOOL rc;
|
|
rc = SetEvent( (SIG) pv );
|
|
Assert( rc != FALSE );
|
|
}
|
|
|
|
STATIC INLINE DWORD UtilSignalWait( void *pv, long lTimeOut )
|
|
{
|
|
DWORD rc;
|
|
UtilAssertNotInCrit( critJet );
|
|
rc = WaitForSingleObject( (SIG) pv, lTimeOut < 0 ? -1L : lTimeOut );
|
|
return rc;
|
|
}
|
|
|
|
STATIC INLINE DWORD UtilSignalWaitEx( void *pv, long lTimeOut, BOOL fAlertable )
|
|
{
|
|
DWORD rc;
|
|
UtilAssertNotInCrit( critJet );
|
|
rc = WaitForSingleObjectEx( (SIG) pv, lTimeOut < 0 ? -1L : lTimeOut, fAlertable );
|
|
return rc;
|
|
}
|
|
|
|
STATIC INLINE void UtilMultipleSignalWait( int csig, void *pv, BOOL fWaitAll, long lTimeOut )
|
|
{
|
|
DWORD rc;
|
|
UtilAssertNotInCrit( critJet );
|
|
rc = WaitForMultipleObjects( csig, (SIG*) pv, fWaitAll, lTimeOut < 0 ? -1L : lTimeOut );
|
|
}
|
|
|
|
void UtilCloseSignal(void *pv);
|
|
|
|
|
|
// Semaphore
|
|
|
|
typedef HANDLE SEM;
|
|
|
|
#define semNil ( (SEM) 0 )
|
|
|
|
STATIC INLINE ERR ErrUtilSemaphoreCreate( SEM *psem, LONG lInitialCount, LONG lMaximumCount )
|
|
{
|
|
*psem = ( SEM ) CreateSemaphore( NULL, lInitialCount, lMaximumCount, NULL );
|
|
return ( *psem == semNil ) ? ErrERRCheck( JET_errOutOfMemory ) : JET_errSuccess;
|
|
}
|
|
|
|
STATIC INLINE DWORD UtilSemaphoreWait( SEM sem, long lTimeOut )
|
|
{
|
|
DWORD rc;
|
|
rc = WaitForSingleObject( (HANDLE) sem, lTimeOut < 0 ? -1L : lTimeOut );
|
|
return rc;
|
|
}
|
|
|
|
STATIC INLINE DWORD UtilSemaphoreRelease( SEM sem, LONG cReleaseCount )
|
|
{
|
|
DWORD rc;
|
|
rc = ReleaseSemaphore( (HANDLE) sem, cReleaseCount, NULL );
|
|
Assert( rc != 0 );
|
|
return rc;
|
|
}
|
|
|
|
void UtilCloseSemaphore(void *pv);
|
|
|
|
|
|
// Threads and Processes
|
|
#define cmsecSleepMax (60*1000)
|
|
VOID UtilSleepEx( ULONG ulTime, BOOL fAlert );
|
|
VOID UtilSleep( ULONG ulTime );
|
|
|
|
ERR ErrUtilCreateThread( ULONG (*pulfn)(), ULONG cbStack, LONG lThreadPriority, HANDLE *phandle );
|
|
ULONG UtilEndThread( HANDLE hThread, SIG sigEnd );
|
|
#define lThreadPriorityNormal 0
|
|
#define lThreadPriorityHigh 1
|
|
void UtilSetThreadPriority( HANDLE hThread, LONG lThreadPriority );
|
|
|
|
STATIC INLINE HANDLE UtilGetCurrentTask( VOID ) { return LongToHandle(GetCurrentProcessId()); }
|
|
STATIC INLINE DWORD DwUtilGetCurrentThreadId( VOID ) { return GetCurrentThreadId(); }
|
|
|
|
// text normalization
|
|
|
|
ERR ErrUtilCheckLangid( LANGID *plangid );
|
|
VOID UtilNormText( char *rgchText, INT cchText, BYTE *rgchNorm, INT cbNorm, INT *pbNorm );
|
|
ERR ErrUtilNormText(
|
|
const BYTE *pbField,
|
|
INT cbField,
|
|
INT cbKeyBufLeft,
|
|
BYTE *pbSeg,
|
|
INT *pcbSeg );
|
|
|
|
#define BINARY_NAMES 1
|
|
#ifdef BINARY_NAMES
|
|
#define UtilCmpName( sz1, sz2 ) \
|
|
( _stricmp( sz1, sz2 ) )
|
|
#define UtilStringCompare( pb1, cb1, pb2, cb2, sort, plResult ) \
|
|
{ \
|
|
*plResult = strncmp( pb1, pb2, min( cb1, cb2 ) ); \
|
|
if ( !*plResult ) \
|
|
*plResult = cb1 > cb2; \
|
|
}
|
|
#else
|
|
INT UtilCmpName( const char *sz1, const char *sz2 );
|
|
VOID UtilStringCompare( char *pb1, unsigned long cb1,
|
|
char *pb2, unsigned long cb2, unsigned long sort,
|
|
long *plResult );
|
|
#endif
|
|
|
|
// Unicode Support
|
|
|
|
ERR ErrUtilMapString(LANGID langid, BYTE *pbField, INT cbField, BYTE *rgbSeg,
|
|
int cbBufLeft, int *cbSeg);
|
|
ERR ErrUtilWideCharToMultiByte(LPCWSTR lpcwStr, LPSTR *lplpOutStr);
|
|
|
|
|
|
// RFS functions
|
|
|
|
#ifdef RFS2
|
|
int UtilRFSAlloc( const char *szType, int Type );
|
|
int UtilRFSLog(const char *szType,int fPermitscritted);
|
|
void UtilRFSLogJETCall(const char *szFunc,ERR err,const char *szFile,unsigned Line);
|
|
void UtilRFSLogJETErr(ERR err,const char *szLabel,const char *szFile,unsigned szLine);
|
|
#endif /* RFS2 */
|
|
|
|
|
|
/*
|
|
** UtilInterlockedIncrement and UtilInterlockedDecrement are wrapper functions
|
|
** to increment or decrement a value in a thread-safe manner.
|
|
**
|
|
** Return values are:
|
|
**
|
|
** > 0 if resulting value > 0
|
|
** = 0 if resulting value = 0
|
|
** < 0 if resulting value < 0
|
|
**
|
|
** Note that the return value isn't necessary the resulting value; it may be
|
|
** different than the resulting value, but sign is guarenteed to be the same.
|
|
*/
|
|
|
|
STATIC INLINE long UtilInterlockedIncrement( long *lpValue )
|
|
{
|
|
return InterlockedIncrement( lpValue );
|
|
}
|
|
|
|
STATIC INLINE long UtilInterlockedDecrement( long *lpValue )
|
|
{
|
|
return InterlockedDecrement( lpValue );
|
|
}
|
|
|
|
|
|
/*
|
|
** UtilInterlockedExchange is a wrapper function to assign a value to a
|
|
** variable in a thread-safe manner.
|
|
**
|
|
** This function returns the prior value of the variable (before the
|
|
** assignment was done).
|
|
*/
|
|
|
|
STATIC INLINE long UtilInterlockedExchange( long *lpValue1, long lValue2 )
|
|
{
|
|
return InterlockedExchange( lpValue1, lValue2 );
|
|
}
|
|
|
|
|
|
// Debug output
|
|
|
|
#ifdef DEBUG
|
|
extern void * critDBGPrint;
|
|
VOID JET_API DBGFPrintF( char *sz );
|
|
void VARARG DebugWriteString(BOOL fHeader, const char *szFormat, ...);
|
|
#else
|
|
#define DBGFPrintF( sz ) 0
|
|
#endif
|
|
|
|
void UtilPerfDumpStats(char *szText);
|
|
|
|
// End Assert redirection
|
|
|
|
#undef szAssertFilename
|
|
|
|
#endif // _UTILW32_H
|