|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
LogWrappers.h
Abstract:
Helper classes for logging APIs
Author:
Hakki T. Bostanci (hakkib) 06-Apr-2000
Revision History:
--*/
#ifndef LOGWRAPPERS_H
#define LOGWRAPPERS_H
#include <map>
#include "LogWindow.h"
//////////////////////////////////////////////////////////////////////////
//
//
//
#define TLS_NOCONSOLE 0x04000000L
//////////////////////////////////////////////////////////////////////////
//
//
//
#define LOG_LEVELS 0x0000FFFFL // These are used to mask out the
#define LOG_STYLES 0xFFFF0000L // styles or levels from log object.
#define TLS_LOGALL 0x0000FFFFL // Log output. Logs all the time.
#define TLS_LOG 0x00000000L // Log output. Logs all the time.
#define TLS_INFO 0x00002000L // Log information.
#define TLS_ABORT 0x00000001L // Log Abort, then kill process.
#define TLS_SEV1 0x00000002L // Log at Severity 1 level
#define TLS_SEV2 0x00000004L // Log at Severity 2 level
#define TLS_SEV3 0x00000008L // Log at Severity 3 level
#define TLS_WARN 0x00000010L // Log at Warn level
#define TLS_PASS 0x00000020L // Log at Pass level
#define TLS_BLOCK 0x00000400L // Block the variation.
#define TLS_BREAK 0x00000800L // Debugger break;
#define TLS_CALLTREE 0x00000040L // Log call-tree (function tracking).
#define TLS_SYSTEM 0x00000080L // Log System debug.
#define TLS_TESTDEBUG 0x00001000L // Debug level.
#define TLS_TEST 0x00000100L // Log Test information (user).
#define TLS_VARIATION 0x00000200L // Log testcase level.
#define TLS_REFRESH 0x00010000L // Create new file || trunc to zero.
#define TLS_SORT 0x00020000L // Sort file output by instance.
#define TLS_DEBUG 0x00040000L // Output to debug (com) monitor).
#define TLS_MONITOR 0x00080000L // Output to 2nd screen.
#define TLS_PROLOG 0x00200000L // Prolog line information.
#define TLS_WINDOW 0x00400000L // Log to windows.
#define TLS_ACCESSON 0x00800000L // Keep log-file open.
#define TLS_DIFFABLE 0x01000000L // make log file windiff'able (no dates..)
#define TLS_NOHEADER 0x02000000L // suppress headers so it is more diffable
#define TL_LOG TLS_LOG ,_T(__FILE__),(int)__LINE__
#define TL_ABORT TLS_ABORT ,_T(__FILE__),(int)__LINE__
#define TL_SEV1 TLS_SEV1 ,_T(__FILE__),(int)__LINE__
#define TL_SEV2 TLS_SEV2 ,_T(__FILE__),(int)__LINE__
#define TL_SEV3 TLS_SEV3 ,_T(__FILE__),(int)__LINE__
#define TL_WARN TLS_WARN ,_T(__FILE__),(int)__LINE__
#define TL_PASS TLS_PASS ,_T(__FILE__),(int)__LINE__
#define TL_BLOCK TLS_BLOCK ,_T(__FILE__),(int)__LINE__
#define TL_INFO TLS_INFO ,_T(__FILE__),(int)__LINE__
#define TL_BREAK TLS_BREAK ,_T(__FILE__),(int)__LINE__
#define TL_CALLTREE TLS_CALLTREE ,_T(__FILE__),(int)__LINE__
#define TL_SYSTEM TLS_SYSTEM ,_T(__FILE__),(int)__LINE__
#define TL_TESTDEBUG TLS_TESTDEBUG,_T(__FILE__),(int)__LINE__
#define TL_TEST TLS_TEST ,_T(__FILE__),(int)__LINE__
#define TL_VARIATION TLS_VARIATION,_T(__FILE__),(int)__LINE__
//////////////////////////////////////////////////////////////////////////
//
//
//
class CLog { protected: struct CResults { UINT nTotal; UINT nPassed; UINT nWarned; UINT nFailedSev3; UINT nFailedSev2; UINT nFailedSev1; UINT nBlocked; UINT nAborted; DWORD dwStartTime;
CResults() { ZeroMemory(this, sizeof(*this)); dwStartTime = GetTickCount(); }
void Update(DWORD dwLogLevel) { if (dwLogLevel & TLS_PASS) ++nPassed; if (dwLogLevel & TLS_WARN) ++nWarned; if (dwLogLevel & TLS_SEV3) ++nFailedSev3; if (dwLogLevel & TLS_SEV2) ++nFailedSev2; if (dwLogLevel & TLS_SEV1) ++nFailedSev1; if (dwLogLevel & TLS_BLOCK) ++nBlocked; if (dwLogLevel & TLS_ABORT) ++nAborted; }
PCTSTR Report(PTSTR pBuffer, SIZE_T nBufferLen) const { DWORD dwUpTime = GetTickCount() - dwStartTime;
_sntprintf( pBuffer, nBufferLen, _T("%d total, ") _T("%d passed, ") _T("%d warned, ") _T("%d failed sev1, ") _T("%d failed sev2, ") _T("%d failed sev3, ") _T("%d blocked, ") _T("%d aborted tests in ") _T("%d hours, ") _T("%d mins, ") _T("%d secs"), nTotal, nPassed, nWarned, nFailedSev3, nFailedSev2, nFailedSev1, nBlocked, nAborted, dwUpTime / (1000 * 60 * 60), (dwUpTime / (1000 * 60)) % 60, (dwUpTime / 1000) % 60 );
return pBuffer; }
PCTSTR Summary() const { if (nAborted) { return _T("TIMEOUT"); }
if (nBlocked) { return _T("NOCONFIG"); }
if (nFailedSev3 || nFailedSev2 || nFailedSev1) { return _T("FAIL"); }
return _T("PASS"); } };
public: CLog() { m_pLogWindow = 0; m_bMute = false; }
virtual ~CLog() { }
VOID SetLogWindow( CLogWindow *pLogWindow ) { m_pLogWindow = pLogWindow; }
VOID Mute(bool bMute = true) { m_bMute = bMute; }
PCTSTR __cdecl Log( DWORD dwLogLevel, PCTSTR pFile, int nLine, PCTSTR pFormat, ... ) { va_list arglist; va_start(arglist, pFormat);
return LogV(dwLogLevel, pFile, nLine, pFormat, arglist); }
PCTSTR LogV( DWORD dwLogLevel, PCTSTR pFile, int nLine, PCTSTR pFormat, va_list arglist ) { CCppMem<TCHAR> pszStr(bufvprintf(pFormat, arglist));
PCTSTR pszComment = _T("");
if (!m_bMute) { if (dwLogLevel & TLS_TEST) { m_TestResults.Update(dwLogLevel); }
if (dwLogLevel & TLS_VARIATION) { if (dwLogLevel & (TLS_WARN | TLS_SEV1 | TLS_SEV2 | TLS_SEV3 | TLS_ABORT)) { DWORD &rResult = m_ThreadResult[GetCurrentThreadId()];
if (rResult < dwLogLevel) { rResult = dwLogLevel; } } }
if (dwLogLevel & TLS_NOCONSOLE) { dwLogLevel &= ~TLS_NOCONSOLE; } else { if (dwLogLevel & TLS_DEBUG) { if (pFile) { OutputDebugString(pFile); OutputDebugString(_T(" ")); }
OutputDebugString(pszStr); OutputDebugString(_T("\n")); //bugbug: talk about inefficiency...
dwLogLevel &= ~TLS_DEBUG; }
if (m_pLogWindow) { TCHAR Buffer[1024];
pszComment = m_pLogWindow->Log( dwLogLevel, pFile, nLine, pszStr, m_VarResults.Report(Buffer, COUNTOF(Buffer)) ); } else { _ftprintf( dwLogLevel & TLS_INFO ? stdout : stderr, _T("%s\n"), pszStr ); } }
LogStr( dwLogLevel, pFile, nLine, pszStr, pszComment ); }
return pszComment; }
virtual VOID LogStr( DWORD dwLogLevel, PCTSTR pFile, int nLine, PCTSTR pStr, PCTSTR pComment ) { }
virtual VOID StartVariation() { ++m_VarResults.nTotal; m_ThreadResult[GetCurrentThreadId()] = TLS_PASS; }
virtual DWORD EndVariation() { DWORD dwResult = m_ThreadResult[GetCurrentThreadId()]; m_VarResults.Update(dwResult); return dwResult; }
virtual VOID InitThread() { }
virtual VOID DoneThread() { }
virtual VOID StartBlock(PCTSTR pBlockName, BOOL bStamp = TRUE) { }
virtual VOID EndBlock(PCTSTR pBlockName, BOOL bStamp = TRUE) { }
private: CLogWindow *m_pLogWindow; bool m_bMute; protected: CResults m_TestResults; CResults m_VarResults;
std::map<DWORD, DWORD> m_ThreadResult; };
//////////////////////////////////////////////////////////////////////////
//
//
//
class CNtLog : public CHandle<HANDLE, CNtLog>, public CLog { typedef CHandle<HANDLE, CNtLog> handle_type;
public: CNtLog() { }
CNtLog( PCTSTR pszLogFile, DWORD dwLogInfo, LPSECURITY_ATTRIBUTES lpSecAttrs = 0 ) : handle_type((*m_Dll.CreateLogEx)( pszLogFile, dwLogInfo, lpSecAttrs )) { InitThread(); }
void Destroy() { (*m_Dll.ReportStats)(*this); (*m_Dll.RemoveParticipant)(*this); (*m_Dll.DestroyLog)(*this); }
bool IsValid() { return (HANDLE) *this != INVALID_HANDLE_VALUE; }
VOID InitThread() { AddParticipant(); }
VOID DoneThread() { RemoveParticipant(); }
VOID AddParticipant( DWORD dwLevels = 0, int nMachineID = 0 ) const { (*m_Dll.AddParticipant)( *this, dwLevels, nMachineID ); }
VOID RemoveParticipant() const { (*m_Dll.RemoveParticipant)(*this); }
static DWORD ParseCmdLine( PCTSTR pszCmdLine ) { return (*m_Dll.ParseCmdLine)(pszCmdLine); }
int GetLogFileName( PTSTR pszFileName ) const { return (*m_Dll.GetLogFileName)(*this, pszFileName); }
VOID SetLogFileName( PTSTR pszFileName ) const { (*m_Dll.SetLogFileName)(*this, pszFileName); }
DWORD GetLogInfo() const { return (*m_Dll.GetLogInfo)(*this); }
DWORD SetLogInfo( DWORD dwInfo ) const { return (*m_Dll.SetLogInfo)(*this, dwInfo); }
VOID PromptLog( HWND hWnd = 0 ) const { (*m_Dll.PromptLog)(hWnd, *this); }
int GetTestStat( DWORD dwLevel ) const { return (*m_Dll.GetTestStat)(*this, dwLevel); }
int GetVariationStat( DWORD dwLevel ) const { return (*m_Dll.GetVariationStat)(*this, dwLevel); }
VOID ClearTestStats() const { (*m_Dll.ClearTestStats)(*this); }
VOID ClearVariationStats() const { (*m_Dll.ClearVariationStats)(*this); }
VOID StartVariation() { CLog::StartVariation(); (*m_Dll.StartVariation)(*this); }
DWORD EndVariation() { CLog::EndVariation(); return (*m_Dll.EndVariation)(*this); }
VOID ReportStats() const { (*m_Dll.ReportStats)(*this); }
VOID LogStr( DWORD dwLogLevel, PCTSTR pFile, int nLine, PCTSTR pStr, PCTSTR pComment ) { (*m_Dll.Log)( *this, dwLogLevel, pFile, nLine, pComment && *pComment ? _T("%s (%s)") : _T("%s"), pStr, pComment ); }
private: class CNtLogDLL { public: CNtLogDLL() { try { m_NtLog = CLibrary(_T("ntlog.dll"));
CreateLog = CCreateLog (m_NtLog, "tlCreateLog_"_AW); CreateLogEx = CCreateLogEx (m_NtLog, "tlCreateLogEx_"_AW); ParseCmdLine = CParseCmdLine (m_NtLog, "tlParseCmdLine_"_AW); GetLogFileName = CGetLogFileName (m_NtLog, "tlGetLogFileName_"_AW); SetLogFileName = CSetLogFileName (m_NtLog, "tlSetLogFileName_"_AW); LogX = CLogX (m_NtLog, "tlLogX_"_AW); Log = CLog (m_NtLog, "tlLog_"_AW); DestroyLog = CDestroyLog (m_NtLog, "tlDestroyLog"); AddParticipant = CAddParticipant (m_NtLog, "tlAddParticipant"); RemoveParticipant = CRemoveParticipant (m_NtLog, "tlRemoveParticipant"); GetLogInfo = CGetLogInfo (m_NtLog, "tlGetLogInfo"); SetLogInfo = CSetLogInfo (m_NtLog, "tlSetLogInfo"); PromptLog = CPromptLog (m_NtLog, "tlPromptLog"); GetTestStat = CGetTestStat (m_NtLog, "tlGetTestStat"); GetVariationStat = CGetVariationStat (m_NtLog, "tlGetVariationStat"); ClearTestStats = CClearTestStats (m_NtLog, "tlClearTestStats"); ClearVariationStats = CClearVariationStats(m_NtLog, "tlClearVariationStats"); StartVariation = CStartVariation (m_NtLog, "tlStartVariation"); EndVariation = CEndVariation (m_NtLog, "tlEndVariation"); ReportStats = CReportStats (m_NtLog, "tlReportStats"); } catch (...) { //_tprintf(_T("*** Cannot load NTLOG.DLL, no log file will be generated ***\n"));
} }
private: CLibrary m_NtLog;
public: DECL_CWINAPI(HANDLE, APIENTRY, CreateLog, (LPCTSTR, DWORD)); DECL_CWINAPI(HANDLE, APIENTRY, CreateLogEx, (LPCTSTR, DWORD, LPSECURITY_ATTRIBUTES)); DECL_CWINAPI(DWORD, APIENTRY, ParseCmdLine, (LPCTSTR)); DECL_CWINAPI(int, APIENTRY, GetLogFileName, (HANDLE, LPTSTR)); DECL_CWINAPI(BOOL, APIENTRY, SetLogFileName, (HANDLE, LPCTSTR)); DECL_CWINAPI(BOOL, APIENTRY, LogX, (HANDLE, DWORD, LPCTSTR, int, LPCTSTR)); DECL_CWINAPI(BOOL, __cdecl, Log, (HANDLE, DWORD, LPCTSTR, int, LPCTSTR, ...)); DECL_CWINAPI(BOOL, APIENTRY, DestroyLog, (HANDLE)); DECL_CWINAPI(BOOL, APIENTRY, AddParticipant, (HANDLE, DWORD, int)); DECL_CWINAPI(BOOL, APIENTRY, RemoveParticipant, (HANDLE)); DECL_CWINAPI(DWORD, APIENTRY, GetLogInfo, (HANDLE)); DECL_CWINAPI(DWORD, APIENTRY, SetLogInfo, (HANDLE, DWORD)); DECL_CWINAPI(HANDLE, APIENTRY, PromptLog, (HWND, HANDLE)); DECL_CWINAPI(int, APIENTRY, GetTestStat, (HANDLE, DWORD)); DECL_CWINAPI(int, APIENTRY, GetVariationStat, (HANDLE, DWORD)); DECL_CWINAPI(BOOL, APIENTRY, ClearTestStats, (HANDLE)); DECL_CWINAPI(BOOL, APIENTRY, ClearVariationStats, (HANDLE)); DECL_CWINAPI(BOOL, APIENTRY, StartVariation, (HANDLE)); DECL_CWINAPI(DWORD, APIENTRY, EndVariation, (HANDLE)); DECL_CWINAPI(BOOL, APIENTRY, ReportStats, (HANDLE)); };
private: static CNtLogDLL m_Dll; };
//////////////////////////////////////////////////////////////////////////
//
//
//
// Invalid Log handle define
#define INVALID_LOGHANDLE -1
// Log file and debug output flags
#define NO_LOG 0x000000
#define STAT_LOG 0x000001 // Local logging operation
#define SUM_LOG 0x000002
#define ERR_LOG 0x000004
#define DBG_LOG 0x000008
#define SVR_STAT_LOG 0x010000
#define SVR_SUM_LOG 0x020000 // Lormaster Server logging operation
#define SVR_ERR_LOG 0x040000
#define SVR_DBG_LOG 0x080000
#define SVR_SQL_LOG 0x100000 // Perform SQL logging
// LogFile Creation flags
#define LOG_NEW 0x001
#define LOG_APPEND 0x002
#define LOG_NOCREATE 0x004
// Test result type
#define RESULT_INFO 0
#define RESULT_TESTPASS 1
#define RESULT_TESTFAIL 2
#define RESULT_TESTNA 3
#define RESULT_SUMMARY 4
#define RESULT_DEBUG 5
#define RESULT_ERRINFO 6
//////////////////////////////////////////////////////////////////////////
//
//
//
class CLorLog : public CHandle<unsigned long, CLorLog>, public CLog { typedef CHandle<unsigned long, CLorLog> handle_type;
public: CLorLog() { }
CLorLog( const char *pTest_Name, const char *pLog_Path, unsigned long dwCreate_Flags, unsigned long dwLog_Flags, unsigned long dwDebug_Flags ) : handle_type((*m_Dll.RegisterTest)( pTest_Name, pLog_Path, dwCreate_Flags, dwLog_Flags, dwDebug_Flags )) { }
CLorLog( const char *pTest_Name, const char *pLog_Path, DWORD Create_Flags, DWORD Log_Flags, DWORD Debug_Flags, DWORD dwProcessID ) : handle_type((*m_Dll.RegisterTest_ProcID)( pTest_Name, pLog_Path, Create_Flags, Log_Flags, Debug_Flags, dwProcessID )) { }
void Destroy() { (*m_Dll.UnRegisterTest)(*this); }
bool IsValid() { return *this != INVALID_LOGHANDLE; }
VOID LogStr( DWORD dwLogLevel, PCTSTR pFile, int nLine, PCTSTR pStr, PCTSTR pComment ) { DWORD dwType;
if (dwLogLevel & TLS_INFO) { dwType = RESULT_INFO; } else if (dwLogLevel & (TLS_WARN | TLS_SEV1 | TLS_SEV2 | TLS_SEV3 | TLS_ABORT)) { dwType = RESULT_ERRINFO; } else { dwType = RESULT_INFO; }
USES_CONVERSION;
(*m_Dll.TestResultEx)( *this, dwType, pComment && *pComment ? "%1: %2!d!: %3 (%4)" : "%1: %2!d!: %3", T2A(pFile), nLine, T2A(pStr), T2A(pComment) ); }
private: class CLorLogDLL { public: CLorLogDLL() { try { m_LorLog = CLibrary(_T("loglog32.dll"));
RegisterTest = CRegisterTest (m_LorLog, "RegisterTest"); RegisterTest_ProcID = CRegisterTest_ProcID(m_LorLog, "RegisterTest_ProcID"); TestResult = CTestResult (m_LorLog, "TestResult"); TestResultEx = CTestResultEx (m_LorLog, "TestResultEx"); UnRegisterTest = CUnRegisterTest (m_LorLog, "UnRegisterTest"); QueryTestResults = CQueryTestResults (m_LorLog, "QueryTestResults"); } catch (...) { //_tprintf(_T("*** Cannot load LORLOG32.DLL, no log file will be generated ***\n"));
} }
private: CLibrary m_LorLog;
public: DECL_CWINAPI(unsigned long, WINAPI, RegisterTest, (const char *, const char *, unsigned long, unsigned long, unsigned long)); DECL_CWINAPI(unsigned long, WINAPI, RegisterTest_ProcID, (const char *, const char *, DWORD, DWORD, DWORD, DWORD)); DECL_CWINAPI(int, WINAPI, TestResult, (unsigned long, unsigned long, const char *)); DECL_CWINAPI(int, __cdecl, TestResultEx, (unsigned long, unsigned long, const char *, ...)); DECL_CWINAPI(int, WINAPI, UnRegisterTest, (unsigned long)); DECL_CWINAPI(int, WINAPI, QueryTestResults, (unsigned long, unsigned long *, unsigned long *, unsigned long *)); };
private: static CLorLogDLL m_Dll; };
//////////////////////////////////////////////////////////////////////////
//
//
//
#define TIME_TO_STR_FORMAT \
_T("%d/%d/%02d %d:%02d:%02d %cM")
#define TIME_TO_STR_ARGS(st) \
st.wMonth, \ st.wDay, \ st.wYear % 100, \ st.wHour % 12, \ st.wMinute, \ st.wSecond, \ st.wHour / 12 ? _T('P') : _T('A') \
//////////////////////////////////////////////////////////////////////////
//
//
//
class CBvtLog : public CLog { public: struct COwners { PCTSTR pTestName; PCTSTR pContactName; PCTSTR pMgrName; PCTSTR pDevPrimeName; PCTSTR pDevAltName; PCTSTR pTestPrimeName; PCTSTR pTestAltName; };
public: CBvtLog() { }
CBvtLog( COwners *pOwners, PCTSTR filename, PCTSTR mode = _T("at"), int shflag = _SH_DENYWR ) : m_nIntent(0), m_nBlock(0), m_pOwners(pOwners), m_LogFile(filename, mode, shflag) { setvbuf(m_LogFile, 0, _IONBF, 0);
GetLocalTime(&m_StartTime);
StartBlock(_T("TESTRESULT"), FALSE); }
~CBvtLog() { GetLocalTime(&m_EndTime);
ReportStats();
EndBlock(_T("TESTRESULT"), FALSE); }
VOID ReportStats() const { _ftprintf( m_LogFile, _T("\n") _T("%*sTEST: %s\n") _T("%*sRESULT: %s\n") _T("%*sBUILD: %d\n") _T("%*sMACHINE: %s\n") _T("%*sCONTACT: %s\n") _T("%*sMGR CONTACT: %s\n") _T("%*sDEV PRIME: %s\n") _T("%*sDEV ALT: %s\n") _T("%*sTEST PRIME: %s\n") _T("%*sTEST ALT: %s\n") _T("%*sSTART TIME: ") TIME_TO_STR_FORMAT _T("\n") _T("%*sEND TIME: ") TIME_TO_STR_FORMAT _T("\n") _T("\n"), m_nIntent, _T(""), m_pOwners->pTestName, m_nIntent, _T(""), m_VarResults.Summary(), //bugbug
m_nIntent, _T(""), COSVersionInfo().dwBuildNumber, m_nIntent, _T(""), (PCTSTR) CComputerName(TRUE), m_nIntent, _T(""), m_pOwners->pContactName, m_nIntent, _T(""), m_pOwners->pMgrName, m_nIntent, _T(""), m_pOwners->pDevPrimeName, m_nIntent, _T(""), m_pOwners->pDevAltName, m_nIntent, _T(""), m_pOwners->pTestPrimeName, m_nIntent, _T(""), m_pOwners->pTestAltName, m_nIntent, _T(""), TIME_TO_STR_ARGS(m_StartTime), m_nIntent, _T(""), TIME_TO_STR_ARGS(m_EndTime) ); }
VOID LogStr( DWORD dwLogLevel, PCTSTR pFile, int nLine, PCTSTR pStr, PCTSTR pComment ) { PCTSTR pszText; int iImage; CLogWindow::FindNtLogLevel(dwLogLevel, &pszText, &iImage);
_ftprintf( m_LogFile, pComment && *pComment ? _T("%*s%s: %s (%s)\n") : _T("%*s%s: %s\n"), m_nIntent, _T(""), pszText, pStr, pComment ); }
VOID StartBlock(PCTSTR pBlockName, BOOL bStamp /*= TRUE*/) { SYSTEMTIME st; GetLocalTime(&st);
_ftprintf( m_LogFile, bStamp ? _T("%*s[%s %d - ") TIME_TO_STR_FORMAT _T("]\n") : _T("%*s[%s]\n"), m_nIntent, _T(""), pBlockName, InterlockedIncrement(&m_nBlock), TIME_TO_STR_ARGS(st) ); m_nIntent += 4; }
VOID EndBlock(PCTSTR pBlockName, BOOL bStamp /*= TRUE*/) { m_nIntent -= 4;
SYSTEMTIME st; GetLocalTime(&st);
_ftprintf( m_LogFile, bStamp ? _T("%*s[/%s - ") TIME_TO_STR_FORMAT _T("]\n\n") : _T("%*s[/%s]\n\n"), m_nIntent, _T(""), pBlockName, TIME_TO_STR_ARGS(st) ); }
private: public: COwners *m_pOwners;
CCFile m_LogFile; SYSTEMTIME m_StartTime; SYSTEMTIME m_EndTime;
int m_nIntent; //bugbug
LONG m_nBlock; };
//////////////////////////////////////////////////////////////////////////
//
//
//
extern CCppMem<CLog> g_pLog;
//////////////////////////////////////////////////////////////////////////
//
//
//
template <DWORD dwLogLevel> struct CLogHelper { PCTSTR __cdecl operator ()( PCTSTR pFormat, ... ) { va_list arglist; va_start(arglist, pFormat);
return g_pLog->LogV(dwLogLevel, _T(""), 0, pFormat, arglist); } };
#endif LOGWRAPPERS_H
|