/*++ Copyright (c) 1997 Microsoft Corporation Module Name: eventlog.cpp Abstract: This module defines the generic class for logging events. Because Windows9x does not have system event logging mechanism we emulate it with text file Author: Vlad Sadovsky (VladS) 01-Feb-1997 Environment: User Mode - Win32 History: 22-Sep-1997 VladS created 29-Sep-1997 VladS Added native NT event logging calls --*/ // // Include Headers // #include "cplusinc.h" #include "sticomm.h" #include #include # define PSZ_EVENTLOG_REG_ENTRY \ TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\") # define PSZ_PARAMETERS_REG_ENTRY TEXT("EventMessageFile") # define PSZ_TYPES_REG_ENTRY TEXT("TypesSupported") #ifndef WINNT #include // // Definitions for Win9x event logging ( which is based on text file) // # define PSZ_EVENT_LOG_FILE_DIRECTORY_A "EventLogDirectory" # define PSZ_EVENT_LOG_FILE__A "\\Sti_Event.log" // // Static variables, common for all event loggin objects // // static const TCHAR szMutexNamePrefix[] = TEXT("StiEventLogMutex"); MUTEX_OBJ EventLogSync(szMutexNamePrefix); #endif WINNT LONG lTotalLoggers = 0; HANDLE hEventLogFile = INVALID_HANDLE_VALUE; // // Functions // // inline BOOL FormatStdTime( IN const SYSTEMTIME * pstNow, IN OUT TCHAR * pchBuffer, IN int cbBuffer) { return ( GetTimeFormat( LOCALE_SYSTEM_DEFAULT, ( LOCALE_NOUSEROVERRIDE | TIME_FORCE24HOURFORMAT| TIME_NOTIMEMARKER), pstNow, NULL, pchBuffer, cbBuffer) != 0); } // FormatStdTime() inline BOOL FormatStdDate( IN const SYSTEMTIME * pstNow, IN OUT TCHAR * pchBuffer, IN int cbBuffer) { return ( GetDateFormat( LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE, pstNow, NULL, pchBuffer, cbBuffer) != 0); } // FormatStdDate() EVENT_LOG::EVENT_LOG( LPCTSTR lpszSource) /*++ Description Constructor function for given event log object. Initializes event logging services. Arguments: lpszSource: Source string for the Event source module Note: This is intended to be executed once only. This is not to be used for creating multiple event log handles for same given source name. But can be used for creating EVENT_LOG objects for different source names. --*/ { m_ErrorCode = NO_ERROR; m_lpszSource = lpszSource; m_hEventSource = INVALID_HANDLE_VALUE; #ifdef WINNT // // Register as an event source. // m_ErrorCode = NO_ERROR; m_lpszSource = lpszSource; m_hEventSource = RegisterEventSource( NULL, lpszSource); if( m_hEventSource == NULL ) { // // An Error in initializing the event log. // m_ErrorCode = GetLastError(); } // // Success! // #else // // Windows 9x specific code // CHAR szFilePath[MAX_PATH+1]; CHAR szKeyName[MAX_PATH+1]; DWORD cbBuffer; HKEY hKey; *szFilePath = TEXT('\0'); // // If file has not been opened yet - try to do it now // Nb: Speed is not critical here, because it is unlikely to have threads // competing, so we use not vey efficient locking EventLogSync.Lock(); if ( 0 == lTotalLoggers && ( hEventLogFile == INVALID_HANDLE_VALUE)) { // // Nobody logging yet - open file // lstrcpy(szKeyName,REGSTR_PATH_STICONTROL_A); cbBuffer = sizeof(szFilePath); m_ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS, &hKey); if ( m_ErrorCode == NO_ERROR) { // // Read the value into buffer // *szFilePath = TEXT('\0'); m_ErrorCode = RegQueryValueEx( hKey, REGSTR_VAL_EVENT_LOG_DIRECTORY_A, NULL, NULL, (LPBYTE) szFilePath, &cbBuffer); RegCloseKey( hKey); } // If we did not get log file directory - use system if ((NOERROR != m_ErrorCode) || !*szFilePath ) { m_ErrorCode = ExpandEnvironmentStrings(TEXT("USERPROFILE"), szFilePath, sizeof(szFilePath) / sizeof(szFilePath[0])); } if (*szFilePath ) { lstrcat(szFilePath,PSZ_EVENT_LOG_FILE__A); hEventLogFile = CreateFile(szFilePath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, // security attributes OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // template file handle if ( hEventLogFile != INVALID_HANDLE_VALUE) { // set the file pointer at the end of the file (append mode) if ( SetFilePointer( hEventLogFile, 0, NULL, FILE_END) == (DWORD) -1L) { hEventLogFile = INVALID_HANDLE_VALUE; CloseHandle(hEventLogFile); } } } /* endif ValidPath */ } /* endif no loggers */ InterlockedIncrement(&lTotalLoggers); EventLogSync.Unlock(); if( hEventLogFile != INVALID_HANDLE_VALUE) { // // If log file successfully opened - register event message source file. // On Win9x registration simply means locating module handle for DLL , where we will // load messages from // lstrcpy(szKeyName,PSZ_EVENTLOG_REG_ENTRY); lstrcat(szKeyName,lpszSource); m_ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS, &hKey); if ( m_ErrorCode == NO_ERROR) { // // Read the value into buffer // cbBuffer = sizeof(szFilePath); *szFilePath = TEXT('\0'); m_ErrorCode = RegQueryValueEx( hKey, PSZ_PARAMETERS_REG_ENTRY, NULL, NULL, (LPBYTE) szFilePath, &cbBuffer); RegCloseKey( hKey); if ((NOERROR == m_ErrorCode) && (*szFilePath)) { m_hEventSource = GetModuleHandle(szFilePath); //ASSERT( m_hEventSource != NULL); } } if (NO_ERROR == m_ErrorCode) { } else { // // An Error in initializing the event log. // } } else { // // An Error in initializing the event log. // m_ErrorCode = GetLastError(); DPRINTF(DM_ERROR,"Could not create log file (%s) ( Error %lu)\n", szFilePath, m_ErrorCode); } m_ErrorCode = NO_ERROR; #endif // WINNT } /* EVENT_LOG::EVENT_LOG() */ EVENT_LOG::~EVENT_LOG( VOID) /*++ Description: Destructor function for given EVENT_LOG object. Terminates event logging functions and closes event log handle --*/ { #ifdef WINNT // // If there is a valid Events handle, deregister it // if ( m_hEventSource != NULL) { BOOL fSuccess; fSuccess = DeregisterEventSource( m_hEventSource); if ( !fSuccess) { // // An Error in DeRegistering // m_ErrorCode = GetLastError(); DPRINTF( DM_ERROR, TEXT("Termination of EventLog for %s failed.error %lu\n"),m_lpszSource,m_ErrorCode); } // // Reset the handle's value. Just as a precaution // m_hEventSource = NULL; } #else TAKE_MUTEX_OBJ t(EventLogSync); InterlockedDecrement(&lTotalLoggers); if ( 0 == lTotalLoggers ) { if (hEventLogFile != INVALID_HANDLE_VALUE) { FlushFileBuffers( hEventLogFile); CloseHandle(hEventLogFile); hEventLogFile = INVALID_HANDLE_VALUE; } } #endif } /* EVENT_LOG::~EVENT_LOG() */ VOID EVENT_LOG::LogEvent( IN DWORD idMessage, IN WORD nSubStrings, IN const CHAR * rgpszSubStrings[], IN DWORD errCode) /*++ Description: Log an event to the event logger Arguments: idMessage Identifies the event message nSubStrings Number of substrings to include in this message. (Maybe 0) rgpszSubStrings array of substrings included in the message (Maybe NULL if nSubStrings == 0) errCode An error code from Win32 or NT_STATUS. If this is not Zero, it is considered as "raw" data to be included in message Returns: None --*/ { WORD wType; // Type of Event to be logged // // Find type of message for the event log // if ( NT_INFORMATION( idMessage)) { wType = EVENTLOG_INFORMATION_TYPE; } else if ( NT_WARNING( idMessage)) { wType = EVENTLOG_WARNING_TYPE; } else if ( NT_ERROR( idMessage)) { wType = EVENTLOG_ERROR_TYPE; } else { wType = EVENTLOG_ERROR_TYPE; } // // Log the event // EVENT_LOG::LogEventPrivate( idMessage, wType, nSubStrings, rgpszSubStrings, errCode); return; } /* EVENT_LOG::LogEvent() */ VOID EVENT_LOG::LogEvent( IN DWORD idMessage, IN WORD nSubStrings, IN WCHAR * rgpszSubStrings[], IN DWORD errCode) /*++ Description: Simple Unicode wrapper Arguments: idMessage Identifies the event message nSubStrings Number of substrings to include in this message. (Maybe 0) rgpszSubStrings array of substrings included in the message (Maybe NULL if nSubStrings == 0) errCode An error code from Win32 or WinSock or NT_STATUS. If this is not Zero, it is considered as "raw" data to be included in message Returns: None --*/ { LPCSTR * apsz; DWORD cch; DWORD i; WORD nUsedSubStrings = nSubStrings; static const CHAR *szEmptyString = ""; __try { apsz = new LPCSTR[nSubStrings]; if ( !apsz ) { nUsedSubStrings = 0; __leave; } ZeroMemory(apsz, nSubStrings * sizeof(apsz[0])); // // Convert the array of Wide char parameters // for ( i = 0; i < nSubStrings; i++ ) { UINT cb; cb = (wcslen( rgpszSubStrings[i] ) + 1) * sizeof(CHAR); apsz[i] = new CHAR[cb]; if (!apsz[i]) { // // Ouch, we can't event convert the memory for the parameters. // We'll just log the error without the params then // nUsedSubStrings = 0; __leave; } cch = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, rgpszSubStrings[i], -1, (LPSTR)apsz[i], cb, NULL, NULL ); *((CHAR *) apsz[i] + cb) = '\0'; } } __finally { // // If no substrings, then nothing to convert // LogEvent( idMessage, nUsedSubStrings, nUsedSubStrings ? apsz : &szEmptyString, errCode ); if (apsz) { for ( i = 0; i < nSubStrings; i++ ) { if (apsz[i]) { delete [] (VOID *)apsz[i]; } } delete [] apsz; } } } // // Private functions. // VOID EVENT_LOG::LogEventPrivate( IN DWORD idMessage, IN WORD wEventType, IN WORD nSubStrings, IN const CHAR * apszSubStrings[], IN DWORD errCode ) /*++ Description: Log an event to the event logger. ( Private version, includes EventType) Arguments: idMessage Identifies the event message wEventType Specifies the severety of the event (error, warning, or informational). nSubStrings Number of substrings to include in this message. (Maybe 0) apszSubStrings array of substrings included in the message (Maybe NULL if nSubStrings == 0) errCode An error code from Win32 or NT_STATUS. If this is not Zero, it is considered as "raw" data to be included in message Returns: None --*/ { VOID * pRawData = NULL; DWORD cbRawData = 0; BOOL fReturn; DWORD cch,cbWritten; #ifdef WINNT BOOL fReport; ASSERT( (nSubStrings == 0) || (apszSubStrings != NULL)); ASSERTSZ( (m_hEventSource != NULL),TEXT("Event log handle is not valid")); if( errCode != 0 ) { pRawData = &errCode; cbRawData = sizeof(errCode); } m_ErrorCode = NO_ERROR; fReport = ReportEvent( m_hEventSource, // hEventSource wEventType, // fwEventType 0, // fwCategory idMessage, // IDEvent NULL, // pUserSid, nSubStrings, // cStrings cbRawData, // cbData (LPCTSTR *) apszSubStrings, // plpszStrings pRawData ); // lpvData if (!fReport) { m_ErrorCode = GetLastError(); } #else //CHAR szErrCodeString[20]; CHAR *pchBuff = NULL; SYSTEMTIME stCurrentTime; CHAR szFmtTime[32]; CHAR szFmtDate[32]; CHAR szErrorText[MAX_PATH] = {'\0'}; if( (hEventLogFile == INVALID_HANDLE_VALUE) || (m_hEventSource == INVALID_HANDLE_VALUE) ) { return; } if( errCode != 0 ) { pRawData = &errCode; cbRawData = sizeof(errCode); } m_ErrorCode = NO_ERROR; // // Write name of the service, date and time, severity // *szFmtTime = *szFmtDate = '\0'; GetLocalTime(&stCurrentTime); FormatStdTime( &stCurrentTime, szFmtTime, 15); FormatStdDate( &stCurrentTime, szFmtDate, 15); wsprintf(szErrorText,"[%s] %s %s :",m_lpszSource,szFmtDate,szFmtTime); WriteFile(hEventLogFile, szErrorText, lstrlen(szErrorText), &cbWritten, NULL); // // Read message and add inserts // cch = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, m_hEventSource, idMessage, 0, (LPSTR) &pchBuff, 1024, (va_list *)apszSubStrings ); if (cch ) { TAKE_MUTEX_OBJ t(EventLogSync); fReturn = WriteFile(hEventLogFile,pchBuff,cch,&cbWritten,NULL); LocalFree(pchBuff); if (cbWritten) { WriteFile(hEventLogFile,"\n\r",2,&cbWritten,NULL); return ; } } m_ErrorCode = GetLastError(); #endif } /* EVENT_LOG::~LogEventPrivate() */ VOID WINAPI RegisterStiEventSources( VOID ) /*++ Description: Adds necessary registry entry when installing service Arguments: Returns: None --*/ { RegEntry re(PSZ_EVENTLOG_REG_ENTRY,HKEY_LOCAL_MACHINE); re.SetValue(PSZ_PARAMETERS_REG_ENTRY,STI_IMAGE_NAME); re.SetValue(PSZ_TYPES_REG_ENTRY,7); } /********************************* End of File ***************************/