#if !defined ( _WEBEVENTPROBE_H_ )
#define _WEBEVENTPROBE_H_
#include "resource.h"
class CWebEventProbe : public CHttpServer
{
private:
BOOL m_bHaveIPAddress;
CString m_oIPAddress;
public:
CWebEventProbe();
~CWebEventProbe();
// Overrides
//{{AFX_VIRTUAL(CWebEventProbe)
public:
virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer);
//}}AFX_VIRTUAL
DWORD HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB );
void SendEventLog ( CHttpServerContext* pCtxt,
LPCTSTR pchHostName,
LPCTSTR pchEventType,
LPCTSTR pchRecsInPage );
void GetNextPage( CHttpServerContext* pCtxt,
LPCTSTR pchHostName,
LPCTSTR pchEventType,
LPCTSTR pchFirstRec,
LPCTSTR pchRecsInPage );
void GetRecords( CHttpServerContext* pCtxt,
LPCTSTR pchHostName,
LPCTSTR pchEventType,
DWORD dwStartAt,
DWORD dwFetchSize );
void OutputHiddenVariable( CHttpServerContext* pCtxt,
const char* pchVarName,
const char* pchValue );
void OutputHiddenVariable( CHttpServerContext* pCtxt,
const char* pchVarName,
DWORD dwValue );
void OutputTableHeader( CHttpServerContext* pCtxt,
const char* pchCaption,
const char* pchEventType );
void OpenTable( CHttpServerContext* pCtxt,
const char* pchCaption,
const char* pchEventType );
void OutputEventRow( CHttpServerContext* pCtxt,
CEventLogRecord& roEventRecord );
void CloseTable( CHttpServerContext* pCtxt );
BOOL GetHostAddress( CString& roString );
DECLARE_PARSE_MAP()
//{{AFX_MSG(CWebEventProbe)
//}}AFX_MSG
};
#endif
#define WIN32_LEAN_AND_MEAN 1
#include "stdafx.h"
#include "winsock.h"
#include "CRegistry.h"
#include "CEventLog.h"
#include "CEventLogRecord.h"
#include "CWebEventProbe.h"
CWinApp theApp;
CWebEventProbe theExtension;
BEGIN_PARSE_MAP(CWebEventProbe, CHttpServer)
ON_PARSE_COMMAND(SendEventLog, CWebEventProbe,ITS_PSTR ITS_PSTR ITS_PSTR )
ON_PARSE_COMMAND_PARAMS("HostName EventType NumRecsInPage")
ON_PARSE_COMMAND( GetNextPage, CWebEventProbe,
ITS_PSTR ITS_PSTR ITS_PSTR ITS_PSTR )
ON_PARSE_COMMAND_PARAMS("SourceServer EventLogType FirstPageRec NumRecsInPage")
END_PARSE_MAP( CWebEventProbe )
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::CWebEventProbe
DESCRIPTION: ctor
INPUT: none
OUTPUT: none
RETURNS: none
*/
CWebEventProbe::CWebEventProbe()
{
m_bHaveIPAddress = GetHostAddress( m_oIPAddress );
}
/* End of function "CWebEventProbe::CWebEventProbe"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::~CWebEventProbe
DESCRIPTION: dtor
INPUT: none
OUTPUT: none
RETURNS: none
*/
CWebEventProbe::~CWebEventProbe()
{
}
/* End of function "CWebEventProbe::~CWebEventProbe"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::GetHostAddress
DESCRIPTION: Gets the IP address for the host of this dll instance
INPUT: roString - reference to a CString for output
OUTPUT: contents of roString are modified
RETURNS: TRUE if the function worked, FALSE otherwise
*/
BOOL CWebEventProbe::GetHostAddress( CString& roString )
{
DWORD MaxNameLength = MAX_COMPUTERNAME_LENGTH + 1;
char lpszHostName[MAX_COMPUTERNAME_LENGTH + 1];
PHOSTENT phostent;
IN_ADDR inaddr;
roString = _T("localhost");
if ( ! GetComputerName( (LPTSTR)lpszHostName, (LPDWORD) &MaxNameLength) )
{
return FALSE;
}
if ((phostent = gethostbyname(lpszHostName)) == NULL)
{
return FALSE;
}
memcpy( &inaddr, phostent->h_addr,4 );
roString = inet_ntoa( inaddr );
return TRUE;
}
/* End of function "CWebEventProbe::GetHostAddress"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::GetExtensionVersion
DESCRIPTION: called by IIS to determine the type of ISAPI dll this is
INPUT: pVer - see mfc docs
OUTPUT: none
RETURNS: TRUE
*/
BOOL CWebEventProbe::GetExtensionVersion( HSE_VERSION_INFO* pVer )
{
CHttpServer::GetExtensionVersion( pVer );
TCHAR sz[ HSE_MAX_EXT_DLL_NAME_LEN+1 ];
ISAPIVERIFY( ::LoadString( AfxGetResourceHandle(),
IDS_SERVER,
sz,
HSE_MAX_EXT_DLL_NAME_LEN ) );
_tcscpy( pVer->lpszExtensionDesc, sz );
return TRUE;
}
/* End of function "CWebEventProbe::GetExtensionVersion"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: SendEventLog
DESCRIPTION: Returns a specific event log to the caller from the specified host.
INPUT: pCtxt - see mfc docs
pchHostName - the host to connect to get the log from
pchEventType - the specific type of event log to request
pchRecsInPage - the number of records the user want to pull on this request
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::SendEventLog( CHttpServerContext* pCtxt,
LPCTSTR pchHostName,
LPCTSTR pchEventType,
LPCTSTR pchRecsInPage )
{
StartContent( pCtxt );
WriteTitle( pCtxt );
if ( !strlen( pchHostName ) )
{
*pCtxt << _T( "ERROR: No Host Specified!\r\n" );
EndContent( pCtxt );
return;
}
// if the user chose to clip the page length, then set the loop bound
// to the users selection. if the caller chose all records, then just
// let the record count stay where it was
//
DWORD dwNumEvents = 10000;
if ( !strstr( pchRecsInPage, "all" ) )
dwNumEvents = atoi( pchRecsInPage );
GetRecords( pCtxt, pchHostName, pchEventType, 0, dwNumEvents );
EndContent( pCtxt );
}
/* End of function "CWebEventProbe::SendEventLog"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::GetNextPage
DESCRIPTION: shell function that calls subordinate to get the next page of records
INPUT: pCtxt - the connection context
pchHostName - the server to get the log from
pchEventType - the log type to get
pchFirstRec - the first record to request
pchRecsInPage - the number of records to fetch
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::GetNextPage( CHttpServerContext* pCtxt,
LPCTSTR pchHostName,
LPCTSTR pchEventType,
LPCTSTR pchFirstRec,
LPCTSTR pchRecsInPage )
{
StartContent( pCtxt );
WriteTitle( pCtxt );
DWORD dwStartAt = 0;
DWORD dwNumEvents = 0;
dwStartAt = atol( pchFirstRec );
dwNumEvents = atol( pchRecsInPage );
GetRecords( pCtxt, pchHostName, pchEventType, dwStartAt + dwNumEvents, dwNumEvents );
EndContent( pCtxt );
}
/* End of function "CWebEventProbe::GetNextPage"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::GetRecords
DESCRIPTION: does all the actual work required to get pages of records from the event log
INPUT: pCtxt - the output context for the client connection
pchHostName - the computer name to the get the log from
pchEventType - the event log type to return
dwStartAt - the staring 'offset' into the log
dwFetchSize - the number of records from the base offset
to return
OUTPUT: void
RETURNS: void
*/
void CWebEventProbe::GetRecords( CHttpServerContext* pCtxt,
LPCTSTR pchHostName,
LPCTSTR pchEventType,
DWORD dwStartAt,
DWORD dwFetchSize )
{
DWORD dwLastRecord = 0;
DWORD dwIndex = 0;
DWORD dwNumEvents = 0;
CEventLog oEventLog;
CEventLogRecord oEventRecord;
*pCtxt << _T( "<BODY BGCOLOR=\"#FFFFFF\">" );
// connect to the log file on the specified host
//
if ( oEventLog.OpenEventLog( pchEventType, pchHostName ) == FALSE )
{
*pCtxt << _T( "ERROR: Could Not Connect to Event Log for Host.\r\n" );
EndContent( pCtxt );
return;
}
if ( oEventLog.GetRecordCount( dwNumEvents ) == FALSE )
{
*pCtxt << _T( "ERROR: Could Not Determine Event Log Size.\r\n" );
EndContent( pCtxt );
return;
}
dwLastRecord = oEventLog.GetOldestRecordNumber();
OutputTableHeader( pCtxt, pchHostName, pchEventType );
// advance to the first record that is greater than the
// "start at cursor"
//
while ( dwIndex < dwStartAt )
{
oEventLog.ReadRecord( dwIndex + 1,
oEventRecord,
EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ );
dwIndex++;
}
// now loop over the log file getting records until the count of
// fetched records matches the users request
//
while ( dwIndex < ( dwStartAt + dwFetchSize ) )
{
if ( TRUE == oEventLog.ReadRecord( dwIndex + 1,
oEventRecord,
EVENTLOG_FORWARDS_READ |
EVENTLOG_SEQUENTIAL_READ ) )
{
OutputEventRow( pCtxt, oEventRecord );
}
dwIndex++;
}
CloseTable( pCtxt );
// now if the user did not request the entire log file,
// put out some context data with a simple form wrapper
// in case the user comes back with a 'next page' command
//
// bug bug bug. you may need to replace local host here....
//
if ( !( dwStartAt == 0 ) || !( dwFetchSize == 10000 ) )
{
*pCtxt << _T("<hr><p>");
*pCtxt << _T("<FORM action=\"http://");
*pCtxt << m_oIPAddress;
*pCtxt << _T("/scripts/weasel.dll?GetNextPage\" method=post>");
*pCtxt << _T("<p>");
*pCtxt << _T("<INPUT type=\"submit\" value=\"Get Next Page\">");
OutputHiddenVariable( pCtxt, "EventLogType", pchEventType );
OutputHiddenVariable( pCtxt, "SourceServer", pchHostName );
OutputHiddenVariable( pCtxt, "FirstPageRec", dwStartAt );
OutputHiddenVariable( pCtxt, "NumRecsInPage", dwFetchSize );
*pCtxt << _T("</FORM>");
}
}
/* End of function "CWebEventProbe::GetRecords"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::OutputHiddenVariable
DESCRIPTION: does the work required to output a hidden variable to the
context
INPUT: pCtxt - the client context
pchVarName - the name of the variable
pchValue - the value for the variable
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::OutputHiddenVariable( CHttpServerContext* pCtxt,
const char* pchVarName,
const char* pchValue )
{
*pCtxt << _T("<INPUT TYPE=HIDDEN NAME=");
*pCtxt << pchVarName;
*pCtxt << _T(" VALUE=");
*pCtxt << pchValue;
*pCtxt << _T(">\r\n");
}
/* End of function "CWebEventProbe::OutputHiddenVariable"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::OutputHiddenVariable
DESCRIPTION: does the work required to output a hidden variable to the
context
INPUT: pCtxt - the client context
pchVarName - the name of the variable
dwValue - the value for the variable
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::OutputHiddenVariable( CHttpServerContext* pCtxt,
const char* pchVarName,
DWORD dwValue )
{
*pCtxt << _T("<INPUT TYPE=HIDDEN NAME=");
*pCtxt << pchVarName;
*pCtxt << _T(" VALUE=");
*pCtxt << (long)dwValue;
*pCtxt << _T(">\r\n");
}
/* End of function "CWebEventProbe::OutputHiddenVariable"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::OutputTableHeader
DESCRIPTION: calls on a subordinate to start the table, then outputs the
title row.
INPUT: pCtxt - the client context
pchCaption - the caption text for the table
pchEventType - the type of event log being requested
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::OutputTableHeader( CHttpServerContext* pCtxt,
const char* pchCaption,
const char* pchEventType )
{
OpenTable( pCtxt, pchCaption, pchEventType );
*pCtxt << _T("<TR><TD NOWRAP ALIGN=CENTER VALIGN=CENTER> Event Type </TD>");
*pCtxt << _T("<TD ALIGN=CENTER VALIGN=CENTER> Date </TD>");
*pCtxt << _T("<TD ALIGN=CENTER VALIGN=CENTER> Time </TD>");
*pCtxt << _T("<TD ALIGN=CENTER VALIGN=CENTER> Event Source </TD>");
*pCtxt << _T("<TD ALIGN=CENTER VALIGN=CENTER> Category </TD>");
*pCtxt << _T("<TD NOWRAP ALIGN=CENTER VALIGN=CENTER> Event ID </TD>");
*pCtxt << _T("<TD ALIGN=CENTER VALIGN=CENTER>Message</TD></TR>");
}
/* End of function "CWebEventProbe::OutputTableHeader"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::OpenTable
DESCRIPTION: does the work required to start an HTML table. Optionally
applies a caption
INPUT: pCtxt - the client context
pchCaption - the caption text (can be NULL)
pchEventType - the type of event log being requested
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::OpenTable( CHttpServerContext* pCtxt,
const char* pchCaption,
const char* pchEventType )
{
*pCtxt << _T("<TABLE BORDER>") << _T("\r\n");
if ( NULL != pchCaption )
*pCtxt << _T("<CAPTION ALIGH=TOP> <B><I><FONT SIZE = 5>")
<< pchEventType
<< _T(" Event Log for ")
<< pchCaption
<< _T("</FONT></I></B></CAPTION>") << _T("\r\n");
}
/* End of function "CWebEventProbe::OpenTable"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::CloseTable
DESCRIPTION: closes out a table
INPUT: pCtxt - the output context
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::CloseTable( CHttpServerContext* pCtxt )
{
*pCtxt << _T("</TABLE>") << _T("\r\n\r\n");
}
/* End of function "CWebEventProbe::CloseTable"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::OutputEventRow
DESCRIPTION: does the work required to convert an CEventLogRecord to an
HTML output row.
INPUT: pCtxt - the output context
roEventRecord - the event record to convert/display
OUTPUT: none
RETURNS: void
*/
void CWebEventProbe::OutputEventRow( CHttpServerContext* pCtxt,
CEventLogRecord& roEventRecord )
{
CString oTemp;
// Event Type Cell
//
*pCtxt << _T("<TR><TD>");
switch ( roEventRecord.m_wEventType )
{
// bug bug bug ... you may need to change the path to this gif.....
//
case EVENTLOG_ERROR_TYPE:
*pCtxt << _T("<IMG SRC=HTTP://");
*pCtxt << m_oIPAddress;
*pCtxt << _T("/STOP.GIF ALIGN=MIDDLE ALT=ERROR>");
break;
case EVENTLOG_WARNING_TYPE:
*pCtxt << _T("<IMG SRC=HTTP://");
*pCtxt << m_oIPAddress;
*pCtxt << _T("/WARN.GIF ALIGN=MIDDLE ALT=WARNING>");
break;
case EVENTLOG_INFORMATION_TYPE:
*pCtxt << _T("<IMG SRC=HTTP://");
*pCtxt << m_oIPAddress;
*pCtxt << _T("/INFO.GIF ALIGN=MIDDLE ALT=INFO>");
break;
case EVENTLOG_AUDIT_SUCCESS:
*pCtxt << _T("<IMG SRC=HTTP://");
*pCtxt << m_oIPAddress;
*pCtxt << _T("/INFO.GIF ALIGN=MIDDLE ALT=SUCCESS>");
break;
case EVENTLOG_AUDIT_FAILURE:
*pCtxt << _T("<IMG SRC=HTTP://");
*pCtxt << m_oIPAddress;
*pCtxt << _T("/STOP.GIF ALIGN=MIDDLE ALT=FAILURE>");
break;
}
*pCtxt << _T("</TD>\r\n");
// date part
//
*pCtxt << _T(" <TD>");
oTemp = roEventRecord.m_oTimeGenerated.Format("%m/%d/%Y");
*pCtxt << (const char*) oTemp;
*pCtxt << _T("</TD>\r\n");
// time part
//
*pCtxt << _T(" <TD>");
oTemp = roEventRecord.m_oTimeGenerated.Format("%I:%M:%S%p");
*pCtxt << (const char*) oTemp;
*pCtxt << _T("</TD>\r\n");
// Event Source
//
*pCtxt << _T(" <TD>");
*pCtxt << (const char*) roEventRecord.m_oSource;
*pCtxt << _T("</TD>\r\n");
// Category
//
*pCtxt << _T(" <TD>");
if ( !roEventRecord.m_wEventCategory )
{
oTemp.Format("%u", roEventRecord.m_wEventCategory );
*pCtxt << (const char*) oTemp;
}
else
*pCtxt << (const char*)roEventRecord.m_oCategory;
*pCtxt << _T("</TD>\r\n");
// EventID (masked)
//
*pCtxt << _T(" <TD>");
oTemp.Format("%u", roEventRecord.m_dwEventID & 0x0000FFFF );
*pCtxt << (const char*) oTemp;
*pCtxt << _T("</TD>\r\n");
// Event Message
//
*pCtxt << _T(" <TD>");
*pCtxt << (const char*) roEventRecord.m_oCompleteMsg;
*pCtxt << _T("</TD>") << _T("\r\n\r\n");
}
/* End of function "CWebEventProbe::OutputEventRow"
/*****************************************************************************/
/*****************************************************************************/
/*
FUNCTION NAME: CWebEventProbe::HttpExtensionProc
DESCRIPTION: the entry point
INPUT: pECB -- see mfc docs
OUTPUT: none
RETURNS: DWORD
*/
DWORD CWebEventProbe::HttpExtensionProc( EXTENSION_CONTROL_BLOCK* pECB )
{
return CHttpServer::HttpExtensionProc( pECB );
}
/* End of function "CWebEventProbe::HttpExtensionProc"
/*****************************************************************************/
#if 0
BEGIN_MESSAGE_MAP(CWebEventProbe, CHttpServer)
//{{AFX_MSG_MAP(CWebEventProbe)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0
#if ! defined( _CEVENTLOG_H_ )
#define _CEVENTLOG_H_
class CEventLogRecord;
class CEventLog : public CObject
{
DECLARE_DYNAMIC( CEventLog )
public:
CEventLog();
virtual ~CEventLog();
BOOL Close( void );
BOOL GetRecordCount( DWORD& rdRecCount );
DWORD GetOldestRecordNumber( void );
BOOL OpenEventLog( LPCTSTR pchLogName, LPCTSTR pchComputerName = NULL );
BOOL ReadRecord( DWORD dwRecNum,
CEventLogRecord& roRecOut,
DWORD dwReadMethod = EVENTLOG_FORWARDS_READ |
EVENTLOG_SEQUENTIAL_READ );
BOOL ReadRecord( DWORD dwRecNum,
LPVOID pBuffOut,
DWORD& rdwOutBufSize,
DWORD dwReadMethod = EVENTLOG_FORWARDS_READ |
EVENTLOG_SEQUENTIAL_READ );
BOOL GetRecordInfo( CEventLogRecord& roRecord );
protected:
void Initialize( void );
private:
CString m_oComputerName;
CString m_oLogName;
HANDLE m_hLog;
DWORD m_dwErrorCode;
DWORD m_dwBytesRead;
DWORD m_dwBytesInNextRecord;
private:
// don't allow this class to be passed by value
//
CEventLog( const CEventLog& ){};
CEventLog& operator= ( const CEventLog& ) { return( *this ); };
#if defined( _DEBUG )
virtual void Dump( CDumpContext& roContext ) const;
#endif
};
#endif
/*****************************************************************************/
/* 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: $
*/
/*****************************************************************************/
#if ! defined ( _EVENTLOGRECORD_H_ )
#define _EVENTLOGRECORD_H_
class CEventLogRecord : public CObject
{
public:
CEventLogRecord();
CEventLogRecord( const CEventLogRecord& source );
CEventLogRecord( const EVENTLOGRECORD * source );
virtual ~CEventLogRecord();
// Data
// NOTE: these are kept public for quick and easy access
//
CString m_oSource;
CString m_oCategory;
CString m_oComputerName;
DWORD m_dwRecNum;
DWORD m_dwReserved;
CTime m_oTimeGenerated;
CTime m_oTimeWritten;
DWORD m_dwEventID;
WORD m_wEventType;
WORD m_wEventCategory;
WORD m_wPairedEventFlags;
DWORD m_dwClosingRecNum;
CByteArray m_oUserSID;
CByteArray m_oData;
CStringArray m_oStringArray;
CString m_oCompleteMsg;
// Methods
//
void CopyFrom( const EVENTLOGRECORD* pxSource );
void CopyFrom( const CEventLogRecord& roSource );
void Initialize( void );
#if defined( _DEBUG )
virtual void Dump( CDumpContext& roContext ) const;
#endif
};
#endif
#include "stdafx.h"
#include "CEventLogRecord.h"
#if defined( _DEBUG )
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#if defined( _DEBUG )
#define new DEBUG_NEW
#endif
CEventLogRecord::CEventLogRecord()
{
Initialize();
}
CEventLogRecord::CEventLogRecord( const CEventLogRecord& roSource )
{
Initialize();
CopyFrom( roSource );
}
CEventLogRecord::CEventLogRecord( const EVENTLOGRECORD* pxSource )
{
Initialize();
CopyFrom( pxSource );
}
CEventLogRecord::~CEventLogRecord()
{
Initialize();
}
/*****************************************************************************/
void CEventLogRecord::CopyFrom( const CEventLogRecord& roSource )
{
// don't copy self
if ( &roSource == this )
return;
m_oSource = roSource.m_oSource;
m_oComputerName = roSource.m_oComputerName;
m_dwRecNum = roSource.m_dwRecNum;
m_dwReserved = roSource.m_dwReserved;
m_oTimeGenerated = roSource.m_oTimeGenerated;
m_oTimeWritten = roSource.m_oTimeWritten;
m_dwEventID = roSource.m_dwEventID;
m_wEventType = roSource.m_wEventType;
m_wEventCategory = roSource.m_wEventCategory;
m_wPairedEventFlags = roSource.m_wPairedEventFlags;
m_dwClosingRecNum = roSource.m_dwClosingRecNum;
m_oUserSID.Copy( roSource.m_oUserSID );
m_oData.Copy( roSource.m_oData );
m_oStringArray.Copy( roSource.m_oStringArray );
}
/*****************************************************************************/
void CEventLogRecord::CopyFrom( const EVENTLOGRECORD* pxSource )
{
Initialize();
if ( NULL == pxSource )
return;
try
{
m_dwRecNum = pxSource->RecordNumber;
m_dwReserved = pxSource->Reserved;
m_oTimeGenerated = CTime( pxSource->TimeGenerated );
m_oTimeWritten = CTime( pxSource->TimeWritten );
m_dwEventID = pxSource->EventID;
m_wEventType = pxSource->EventType;
m_wEventCategory = pxSource->EventCategory;
m_wPairedEventFlags = pxSource->ReservedFlags;
m_dwClosingRecNum = pxSource->ClosingRecordNumber;
// Here's where things start to get a little interesting...
BYTE* pByte = (BYTE*) pxSource;
BYTE AddByte = 0;
DWORD dwCurPos = pxSource->UserSidOffset;
DWORD dwIndex = 0;
while( dwIndex < pxSource->UserSidLength )
{
AddByte = pByte[ dwCurPos ];
m_oUserSID.Add( AddByte );
dwCurPos++;
dwIndex++;
}
dwIndex = 0;
dwCurPos = pxSource->DataOffset;
while( dwIndex < pxSource->DataLength )
{
m_oData.Add( pByte[ dwCurPos ] );
dwCurPos++;
dwIndex++;
}
dwCurPos = sizeof( EVENTLOGRECORD );
TCHAR chTemp = 0;
// Next comes the SourceName
while( pByte[ dwCurPos ] != 0 )
{
chTemp = pByte[ dwCurPos ];
m_oSource += chTemp;
dwCurPos++;
}
while( pByte[ dwCurPos ] == 0 )
{
dwCurPos++;
}
// ComputerName
while( pByte[ dwCurPos ] != 0 )
{
m_oComputerName += (TCHAR) pByte[ dwCurPos ];
dwCurPos++;
}
// Strings
CString oStrTemp( _T( "" ) );
int iNumOfStrings = 0;
dwCurPos = pxSource->StringOffset;
while( iNumOfStrings < pxSource->NumStrings )
{
oStrTemp.Empty();
while( pByte[ dwCurPos ] != 0 )
{
chTemp = pByte[ dwCurPos ];
oStrTemp += chTemp;
dwCurPos++;
}
m_oStringArray.Add( oStrTemp );
iNumOfStrings++;
// Advance to the next string
if ( pByte[ dwCurPos ] == 0 && iNumOfStrings < pxSource->NumStrings )
{
while( pByte[ dwCurPos ] == 0 )
{
dwCurPos++;
}
}
}
}
catch( ... )
{
Initialize();
}
}
/*****************************************************************************/
void CEventLogRecord::Initialize( void )
{
m_oSource.Empty();
m_oComputerName.Empty();
m_dwRecNum = 0;
m_dwReserved = 0;
m_oTimeGenerated = CTime( 0 );
m_oTimeWritten = CTime( 0 );
m_dwEventID = 0;
m_wEventType = 0;
m_wEventCategory = 0;
m_wPairedEventFlags = 0;
m_dwClosingRecNum = 0;
m_oUserSID.RemoveAll();
m_oData.RemoveAll();
m_oStringArray.RemoveAll();
}
/*****************************************************************************/
#if defined( _DEBUG )
void CEventLogRecord::Dump( CDumpContext& roContext ) const
{
CObject::Dump( roContext );
roContext << _T( "LogRecord:\n" );
roContext << _T( "{\n" );
roContext << _T( " m_oSource = " ) << m_oSource << _T( "\n" );
roContext << _T( " m_oComputerName = " ) << m_oComputerName << _T( "\n" );
roContext << _T( " m_dwRecNum = " ) << m_dwRecNum << _T( "\n" );
roContext << _T( " m_dwReserved = " ) << m_dwReserved << _T( "\n" );
roContext << _T( " m_oTimeGenerated= " ) << m_oTimeGenerated << _T( "\n" );
roContext << _T( " m_oTimeWritten = " ) << m_oTimeWritten << _T( "\n" );
roContext << _T( " m_dwEventID = " ) << m_dwEventID << _T( "\n" );
roContext << _T( " m_wEventType = " ) << m_wEventType << _T( "\n" );
roContext << _T( " m_wEventCategory= " ) << m_wEventCategory << _T( "\n" );
roContext << _T( " m_wPairedEventFlags = " ) << m_wPairedEventFlags <<
_T( "\n" );
roContext << _T( " m_dwClosingRecNum= " ) << m_dwClosingRecNum <<
_T( "\n" );
roContext << _T( " m_oUserSID = " ) << m_oUserSID << _T( "\n" );
roContext << _T( " m_oData = " ) << m_oData << _T( "\n" );
roContext << _T( " m_oStringArray = " ) << m_oStringArray << _T( "\n" );
roContext << _T( "}\n" );
}
#endif