/////////////////////////////////////////////////////////////////////////////// /* File: eventlog.cpp Description: Implements a subset of the NT event log APIs as a C++ class. CEventLog is intended only to provide a convenient method for writing NT event log messages. No reading of event log entries is supported. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 02/14/98 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// #include "pch.h" #pragma hdrstop #include "eventlog.h" #include "registry.h" TCHAR CEventLog::m_szFmtDec[] = TEXT("%1!d!"); TCHAR CEventLog::m_szFmtHex[] = TEXT("0x%1!X!"); CEventLog::~CEventLog( void ) { DBGTRACE((DM_EVENTLOG, DL_MID, TEXT("CEventLog::~CEventLog"))); Close(); } // // Register the specified event source. // Note that the registry entries must already exist. // HKLM\System\CurrentControlSet\Services\EventLog\Application\ // Requires values "EventMessageFile" and "TypesSupported". // HRESULT CEventLog::Initialize( LPCTSTR pszEventSource ) { DBGTRACE((DM_EVENTLOG, DL_MID, TEXT("CEventLog::Initialize"))); if (NULL != m_hLog) { return S_FALSE; } HRESULT hr = NOERROR; m_hLog = RegisterEventSource(NULL, pszEventSource); if (NULL == m_hLog) { hr = HRESULT_FROM_WIN32(GetLastError()); DBGERROR((TEXT("Error 0x%08X registering event source \"%s\""), hr, pszEventSource)); DBGERROR((TEXT("Run regsvr32 on dskquota.dll"))); } return hr; } // // Deregister the event source. // void CEventLog::Close( void ) { DBGTRACE((DM_EVENTLOG, DL_MID, TEXT("CEventLog::Close"))); if (NULL != m_hLog) { DeregisterEventSource(m_hLog); m_hLog = NULL; } } // // Report an event. No replaceable parameters explicitly specified. // If msg string contains replaceable parameters, use Push() to // build list of replacement strings. // HRESULT CEventLog::ReportEvent( WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, // [optional] LPVOID pvRawData, // [optional] DWORD cbRawData // [optional] ) { DBGTRACE((DM_EVENTLOG, DL_MID, TEXT("CEventLog::ReportEvent"))); if (NULL == m_hLog) { DBGERROR((TEXT("Event log not initialized"))); return E_FAIL; } BOOL bResult = false; HRESULT hr = NOERROR; if (0 < m_rgstrText.Count()) { bResult = ReportEvent(wType, wCategory, dwEventID, m_rgstrText, lpUserSid, pvRawData, cbRawData); m_rgstrText.Clear(); } else { bResult = ::ReportEvent(m_hLog, wType, wCategory, dwEventID, lpUserSid, 0, cbRawData, NULL, pvRawData); } if (!bResult) { // // Special-case ERROR_IO_PENDING. ::ReportEvent will fail with // this error code even when it succeeds. Don't know exactly why // but it does. Treat this as success so we don't get unnecessary // debugger output. // DWORD dwError = GetLastError(); if (ERROR_IO_PENDING != dwError) { hr = HRESULT_FROM_WIN32(dwError); DBGERROR((TEXT("Error 0x%08X reporting event"), hr)); } } return hr; } // // Report an event. Replacement strings are explicitly specified // through an array of CString objects. // HRESULT CEventLog::ReportEvent( WORD wType, WORD wCategory, DWORD dwEventID, const CArray& rgstr, PSID lpUserSid, LPVOID pvRawData, DWORD cbRawData ) { DBGTRACE((DM_EVENTLOG, DL_MID, TEXT("CEventLog::ReportEvent [ with strings ]"))); if (NULL == m_hLog) { DBGERROR((TEXT("Event log not initialized"))); return E_FAIL; } HRESULT hr = NOERROR; int cStrings = rgstr.Count(); array_autoptr rgpsz; if (0 < cStrings) { rgpsz = new LPCTSTR[cStrings]; for (int i = 0; i < cStrings; i++) { rgpsz[i] = rgstr[i].Cstr(); } } if (!::ReportEvent(m_hLog, wType, wCategory, dwEventID, lpUserSid, (WORD)cStrings, cbRawData, rgpsz.get(), pvRawData)) { // // Special-case ERROR_IO_PENDING. ::ReportEvent will fail with // this error code even when it succeeds. Don't know exactly why // but it does. Treat this as success so we don't get unnecessary // debugger output. // DWORD dwError = GetLastError(); if (ERROR_IO_PENDING != dwError) { hr = HRESULT_FROM_WIN32(dwError); DBGERROR((TEXT("Error 0x%08X reporting event"), hr)); } } return hr; } // // Push an HRESULT value onto the stack of replacment strings. // void CEventLog::Push( HRESULT hr, eFmt fmt ) { DBGTRACE((DM_EVENTLOG, DL_LOW, TEXT("CEventLog::Push [ integer ]"))); LPTSTR pszBuffer = NULL; CString s; try { if (eFmtSysErr == fmt) { int cchLoaded = ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, HRESULT_CODE(hr), 0, (LPTSTR)&pszBuffer, 1, NULL); if (NULL != pszBuffer && 0 != cchLoaded) { s = pszBuffer; } } else { s.Format(eFmtDec == fmt ? m_szFmtDec : m_szFmtHex, hr); } m_rgstrText.Append(s); } catch(CAllocException& e) { DBGERROR((TEXT("Out of memory error in CEventLog::Push"))); } LocalFree(pszBuffer); } // // Push a string onto the stack of replacement strings. // void CEventLog::Push( LPCTSTR psz ) { DBGTRACE((DM_EVENTLOG, DL_LOW, TEXT("CEventLog::Push [ string ]"))); try { m_rgstrText.Append(CString(psz)); } catch(CAllocException& e) { DBGERROR((TEXT("Out of memory error in CEventLog::Push"))); } }