/*****************************************************************************/
/* SOURCE FILE */
/*****************************************************************************/
/*
$Archive: $
$Revision: $
$Date: $
$Author: $
Description: Implementation of the NT Event Log Wrapper Class
*/
static char OBJECT_ID[] = "$Revision: $ : $Date: $";
/*****************************************************************************/
#include "stdafx.h"
#include "CRegistry.h"
#include "CEventLogRecord.h"
#include "CEventLog.h"
#if defined( _DEBUG )
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC( CEventLog, CObject );
#if defined( _DEBUG )
#define new DEBUG_NEW
#endif
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::CEventLog
DESCRIPTION: ctor
INPUT: none
OUTPUT: none
RETURNS: inits local vars
*/
CEventLog::CEventLog()
{
Initialize();
}
/* End of function "CEventLog::CEventLog"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::~CEventLog
DESCRIPTION: dtor. cleans up and disconnects from the event log
INPUT: none
OUTPUT: none
RETURNS: none
*/
CEventLog::~CEventLog()
{
if ( INVALID_HANDLE_VALUE != m_hLog )
Close();
Initialize();
}
/* End of function "CEventLog::~CEventLog"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::Initialize
DESCRIPTION: initializes class members
INPUT: none
OUTPUT: none
RETURNS: void
*/
void CEventLog::Initialize( void )
{
m_oComputerName.Empty();
m_oLogName.Empty();
m_hLog = INVALID_HANDLE_VALUE;
m_dwErrorCode = 0;
m_dwBytesRead = 0;
m_dwBytesInNextRecord = 0;
}
/* End of function "CEventLog::Initialize"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::Close
DESCRIPTION: disconnects this from the event log
INPUT: none
OUTPUT: none
RETURNS: TRUE if successful, FALSE otherwise
*/
BOOL CEventLog::Close( void )
{
BOOL bReturn = ::CloseEventLog( m_hLog );
if ( FALSE == bReturn )
m_dwErrorCode = ::GetLastError();
else
bReturn = TRUE;
m_hLog = INVALID_HANDLE_VALUE;
return( bReturn );
}
/* End of function "CEventLog::Close"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::GetRecordCount
DESCRIPTION: returns the number of event records
INPUT: rdwRecCount - the count will go here
OUTPUT: none
RETURNS: TRUE if successful, FALSE otherwise
*/
BOOL CEventLog::GetRecordCount( DWORD& rdwRecCount )
{
rdwRecCount = 0; // set this to a known state in case of API failure
BOOL bReturn = ::GetNumberOfEventLogRecords( m_hLog, &rdwRecCount );
if ( FALSE == bReturn )
m_dwErrorCode = ::GetLastError();
else
bReturn = TRUE;
return( bReturn );
}
/* End of function "CEventLog::GetRecordCount"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::GetOldestRecordNumber
DESCRIPTION: returns the record number of the oldest record in the event log
INPUT: none
OUTPUT: none
RETURNS: the record id of the oldest record in the log
*/
DWORD CEventLog::GetOldestRecordNumber( void )
{
DWORD dwReturn = 0;
if ( FALSE != ::GetOldestEventLogRecord( m_hLog, &dwReturn ) )
return( dwReturn );
m_dwErrorCode = ::GetLastError();
return( 0 );
}
/* End of function "CEventLog::GetOldestRecordNumber"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::OpenEventLog
DESCRIPTION: opens a connection to the event log
INPUT: pchLogName - the log to attach to
pchComputerName - the computer whose log will be opened
OUTPUT: none
RETURNS: TRUE if successful, FALSE otherwise
*/
BOOL CEventLog::OpenEventLog( LPCTSTR pchLogName, LPCTSTR pchComputerName )
{
m_oLogName = pchLogName;
// pchComputerName can be NULL
//
try
{
if ( NULL == pchLogName )
{
m_dwErrorCode = ERROR_INVALID_PARAMETER;
return( FALSE );
}
BOOL bReturn = TRUE;
m_hLog = ::OpenEventLog( pchComputerName, pchLogName );
if ( NULL == m_hLog )
{
m_dwErrorCode = ::GetLastError();
m_hLog = INVALID_HANDLE_VALUE;
bReturn = FALSE;
}
else
{
if ( NULL == pchComputerName )
{
TCHAR achComputerName[ MAX_PATH ];
ZeroMemory( achComputerName, sizeof( achComputerName ) );
DWORD dwSize = sizeof( achComputerName ) / sizeof( *( achComputerName ) );
if ( FALSE != ::GetComputerName( achComputerName, &dwSize ) )
m_oComputerName = achComputerName;
else
m_oComputerName.Empty();
}
else
m_oComputerName = pchComputerName;
}
return( bReturn );
}
catch( ... )
{
m_dwErrorCode = ERROR_EXCEPTION_IN_SERVICE;
return( FALSE );
}
}
/* End of function "CEventLog::OpenEventLog"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::ReadRecord
DESCRIPTION: reads an event record into a CEventLogRecord object
INPUT: dwRecNum - the record id to read
roRecOut - the output for this method
dwReadMethod - the method to use for the read
OUTPUT: roRecOut contents are changed
RETURNS: TRUE if successful, FALSE otherwise
*/
BOOL CEventLog::ReadRecord( DWORD dwRecNum, CEventLogRecord& roRecOut, DWORD dwReadMethod )
{
try
{
if ( INVALID_HANDLE_VALUE == m_hLog )
{
m_dwErrorCode = ERROR_INVALID_PARAMETER;
return( FALSE );
}
BOOL bReturn = FALSE;
BYTE TempBuf[1]; // an address for a 'throw away record'
DWORD dwReadSize = 0;
// First, find out how many bytes we need for this Event Record
//
bReturn = ReadRecord( dwRecNum, TempBuf, dwReadSize, dwReadMethod );
m_dwErrorCode = ::GetLastError();
if ( (FALSE == bReturn ) && ( ERROR_INSUFFICIENT_BUFFER != m_dwErrorCode ) )
return( FALSE );
m_dwErrorCode = 0;
// m_dwBytesInNextRecord now contains the size our pByteBuffer should be
// (see ReadRecord for more info....)
//
BYTE* pByteBuffer = new BYTE[m_dwBytesInNextRecord];
ZeroMemory( pByteBuffer, m_dwBytesInNextRecord );
bReturn = ReadRecord( dwRecNum, pByteBuffer, m_dwBytesInNextRecord, dwReadMethod );
if ( FALSE == bReturn )
m_dwErrorCode = ::GetLastError();
else
roRecOut.CopyFrom( (EVENTLOGRECORD *) pByteBuffer );
delete [] pByteBuffer;
// now get the rest of the event log record information
//
if ( 0 != roRecOut.m_dwEventID )
GetRecordInfo( roRecOut );
return( bReturn );
}
catch( ... )
{
m_dwErrorCode = ERROR_EXCEPTION_IN_SERVICE;
return( FALSE );
}
}
/* End of function "CEventLog::ReadRecord"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::ReadRecord
DESCRIPTION: reads an event log into a memory buffer
INPUT: dwRecNum - the record number to start at
pBuffOut - the area to write the event log record to
rdwOutBufSize - size of the output buffer
dwReadMethod - the method to use to read the record
OUTPUT: none
RETURNS: TRUE if successful, FALSE otherwise
*/
BOOL CEventLog::ReadRecord( DWORD dwRecNum, LPVOID pBuffOut, DWORD& rdwOutBufSize, DWORD dwReadMethod )
{
try
{
if ( ( NULL == pBuffOut ) || ( INVALID_HANDLE_VALUE == m_hLog ) )
{
m_dwErrorCode = ERROR_INVALID_PARAMETER;
return( FALSE );
}
BOOL bReturn = ::ReadEventLog( m_hLog,
dwReadMethod,
dwRecNum,
pBuffOut,
rdwOutBufSize,
&m_dwBytesRead,
&m_dwBytesInNextRecord );
if ( FALSE == bReturn )
m_dwErrorCode = ::GetLastError();
else
bReturn = TRUE;
return( bReturn );
}
catch( ... )
{
m_dwErrorCode = ERROR_EXCEPTION_IN_SERVICE;
return( FALSE );
}
}
/* End of function "CEventLog::ReadRecord"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CEventLog::GetRecordInfo
DESCRIPTION: does all the operations required to provide an "event log"
type message string to the event log record
INPUT: roRecord - reference to a record object
OUTPUT: contents of roRecord are modified
RETURNS: TRUE if successful, FALSE otherwise
*/
BOOL CEventLog::GetRecordInfo( CEventLogRecord& roRecord )
{
char achExpanded[MAX_PATH];
CRegistry oRegistry;
int status = 0;
DWORD dwExpanded;
HMODULE hMod;
LPVOID lpMsgBuffer;
CString oDllName;
int iRet;
// connect to the registry and then to the subkey indicated by the
// source field of the record
//
if ( TRUE != oRegistry.Connect( HKEY_LOCAL_MACHINE, (const char*)m_oComputerName ) )
{
roRecord.m_oCompleteMsg = _T("ERROR: Failed To Connect To Registry.");
return FALSE;
}
CString oRegPath;
oRegPath = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
oRegPath += m_oLogName;
oRegPath += "\\";
oRegPath += roRecord.m_oSource;
if ( TRUE != oRegistry.Open( (const char*)oRegPath, KEY_READ ) )
{
roRecord.m_oCompleteMsg = _T("ERROR: Failed to Open Event Log in Registry.");
return FALSE;
}
// if a category is specifed, get the category string from the message file
//
if ( 0 != roRecord.m_wEventCategory )
{
if ( TRUE != oRegistry.GetValue( "CategoryMessageFile", oDllName ) )
{
roRecord.m_oCategory = _T("NULL");
}
else
{
// Expand environment variable strings in the message DLL path name,
// in case any are there.
//
dwExpanded = ExpandEnvironmentStrings( (const char*)oDllName,
achExpanded, MAX_PATH );
// Now we've got the message DLL name, load the DLL.
//
hMod = LoadLibraryEx( (const char*)achExpanded,
NULL,
DONT_RESOLVE_DLL_REFERENCES );
if ( hMod )
{
iRet = FormatMessage ( FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
hMod,
roRecord.m_wEventCategory,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuffer,
0,
NULL );
FreeLibrary( hMod );
if ( iRet )
roRecord.m_oCategory = (char*) lpMsgBuffer;
else
roRecord.m_oCategory = _T("UNKNOWN");
}
else
roRecord.m_oCategory = _T("NULL");
}
}
// try to get the complete message for this record by using the format
// string from the indicated module, and passing the strings embedded in
// the record as a 'va arg list' for use with the format string
//
if ( TRUE != oRegistry.GetValue( "EventMessageFile", oDllName ) )
{
roRecord.m_oCompleteMsg = _T("ERROR: Failed to Read Message File Source.");
return FALSE;
}
dwExpanded = ExpandEnvironmentStrings( (const char*)oDllName, achExpanded, MAX_PATH );
// Now we've got the message DLL name, load the DLL.
//
hMod = LoadLibraryEx( achExpanded, NULL, DONT_RESOLVE_DLL_REFERENCES );
if ( !hMod )
{
roRecord.m_oCompleteMsg = _T(" Can't find or load message DLL. " );
roRecord.m_oCompleteMsg += _T( "Message DLL must be in path or in current directory." );
return FALSE;
}
// prepare the va arg list by first NULLing out all entries
// then copy a pointer to each of the strings in the record
// into one of the pointers in the arg list
//
char* pvaInsertStrs[128];
for ( int iClear = 0; iClear < 128; iClear++ )
pvaInsertStrs[iClear] = NULL;
if ( roRecord.m_oStringArray.GetSize() > 0 )
{
for ( int iLoop = 0; iLoop < roRecord.m_oStringArray.GetSize(); iLoop++ )
{
CString oTemp = roRecord.m_oStringArray.GetAt(iLoop);
pvaInsertStrs[iLoop] = (char*)(LPCTSTR)oTemp;
}
}
iRet = FormatMessage ( FORMAT_MESSAGE_FROM_HMODULE
| FORMAT_MESSAGE_ARGUMENT_ARRAY
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
hMod,
roRecord.m_dwEventID,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuffer,
0,
pvaInsertStrs );
FreeLibrary( hMod );
if ( 0 == iRet )
{
DWORD dwErr = GetLastError();
FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuffer,
0,
NULL );
// if a message string was return. scan it and clear
// out all \r\n characters that may be present
//
if ( strlen( (const char*)lpMsgBuffer ) )
{
roRecord.m_oCompleteMsg = (const char*)lpMsgBuffer;
int iPos = roRecord.m_oCompleteMsg.Find("\r\n");
while ( (-1) != iPos )
{
roRecord.m_oCompleteMsg.SetAt(iPos, ' ' );
roRecord.m_oCompleteMsg.SetAt(iPos+1, ' ' );
iPos = roRecord.m_oCompleteMsg.Find("\r\n");
}
}
LocalFree( lpMsgBuffer );
return FALSE;
}
else
{
if ( strlen( (const char*)lpMsgBuffer ) )
{
roRecord.m_oCompleteMsg = (const char*)lpMsgBuffer;
int iPos = roRecord.m_oCompleteMsg.Find("\r\n");
while ( (-1) != iPos )
{
roRecord.m_oCompleteMsg.SetAt(iPos, ' ' );
roRecord.m_oCompleteMsg.SetAt(iPos+1, ' ' );
iPos = roRecord.m_oCompleteMsg.Find("\r\n");
}
}
LocalFree( lpMsgBuffer );
return TRUE;
}
return TRUE;
}
/* end of function "CEventLog::GetRecordInfo" */
/*****************************************************************************/
#if defined( _DEBUG )
void CEventLog::Dump( CDumpContext& roContext ) const
{
CObject::Dump( roContext );
roContext << TEXT( "m_hLog = " ) << m_hLog << TEXT( "\n" );
roContext << TEXT( "m_dwErrorCode = " ) << m_dwErrorCode << TEXT( "\n" );
roContext << TEXT( "m_dwBytesRead = " ) << m_dwBytesRead << TEXT( "\n" );
roContext << TEXT( "m_dwBytesInNextRecord = " ) << m_dwBytesInNextRecord << TEXT( "\n" );
roContext << TEXT( "m_oComputerName = \"" ) << m_oComputerName << TEXT( "\"\n" );
roContext << TEXT( "m_oLogName = \"" ) << m_oLogName << TEXT( "\"\n" );
}
#endif
/*****************************************************************************/
/* Check-in history */
/*
*$Log: $
*/
/*****************************************************************************/