Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

728 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. eventlog.cpp
  5. Abstract:
  6. This module defines the generic class for logging events.
  7. Because Windows9x does not have system event logging mechanism
  8. we emulate it with text file
  9. Author:
  10. Vlad Sadovsky (VladS) 01-Feb-1997
  11. Environment:
  12. User Mode - Win32
  13. History:
  14. 22-Sep-1997 VladS created
  15. 29-Sep-1997 VladS Added native NT event logging calls
  16. --*/
  17. //
  18. // Include Headers
  19. //
  20. #include "cplusinc.h"
  21. #include "sticomm.h"
  22. #include <eventlog.h>
  23. #include <stisvc.h>
  24. # define PSZ_EVENTLOG_REG_ENTRY \
  25. TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\")
  26. # define PSZ_PARAMETERS_REG_ENTRY TEXT("EventMessageFile")
  27. # define PSZ_TYPES_REG_ENTRY TEXT("TypesSupported")
  28. #ifndef WINNT
  29. #include <lock.h>
  30. //
  31. // Definitions for Win9x event logging ( which is based on text file)
  32. //
  33. # define PSZ_EVENT_LOG_FILE_DIRECTORY_A "EventLogDirectory"
  34. # define PSZ_EVENT_LOG_FILE__A "\\Sti_Event.log"
  35. //
  36. // Static variables, common for all event loggin objects
  37. //
  38. //
  39. static const TCHAR szMutexNamePrefix[] = TEXT("StiEventLogMutex");
  40. MUTEX_OBJ EventLogSync(szMutexNamePrefix);
  41. #endif WINNT
  42. LONG lTotalLoggers = 0;
  43. HANDLE hEventLogFile = INVALID_HANDLE_VALUE;
  44. //
  45. // Functions
  46. //
  47. //
  48. inline BOOL
  49. FormatStdTime( IN const SYSTEMTIME * pstNow,
  50. IN OUT TCHAR * pchBuffer,
  51. IN int cbBuffer)
  52. {
  53. return ( GetTimeFormat( LOCALE_SYSTEM_DEFAULT,
  54. ( LOCALE_NOUSEROVERRIDE | TIME_FORCE24HOURFORMAT|
  55. TIME_NOTIMEMARKER),
  56. pstNow, NULL, pchBuffer, cbBuffer)
  57. != 0);
  58. } // FormatStdTime()
  59. inline BOOL
  60. FormatStdDate( IN const SYSTEMTIME * pstNow,
  61. IN OUT TCHAR * pchBuffer,
  62. IN int cbBuffer)
  63. {
  64. return ( GetDateFormat( LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE,
  65. pstNow, NULL, pchBuffer, cbBuffer)
  66. != 0);
  67. } // FormatStdDate()
  68. EVENT_LOG::EVENT_LOG( LPCTSTR lpszSource)
  69. /*++
  70. Description
  71. Constructor function for given event log object.
  72. Initializes event logging services.
  73. Arguments:
  74. lpszSource: Source string for the Event source module
  75. Note:
  76. This is intended to be executed once only.
  77. This is not to be used for creating multiple event
  78. log handles for same given source name.
  79. But can be used for creating EVENT_LOG objects for
  80. different source names.
  81. --*/
  82. {
  83. m_ErrorCode = NO_ERROR;
  84. m_lpszSource = lpszSource;
  85. m_hEventSource = INVALID_HANDLE_VALUE;
  86. #ifdef WINNT
  87. //
  88. // Register as an event source.
  89. //
  90. m_ErrorCode = NO_ERROR;
  91. m_lpszSource = lpszSource;
  92. m_hEventSource = RegisterEventSource( NULL, lpszSource);
  93. if( m_hEventSource == NULL ) {
  94. //
  95. // An Error in initializing the event log.
  96. //
  97. m_ErrorCode = GetLastError();
  98. }
  99. //
  100. // Success!
  101. //
  102. #else
  103. //
  104. // Windows 9x specific code
  105. //
  106. CHAR szFilePath[MAX_PATH+1];
  107. CHAR szKeyName[MAX_PATH+1];
  108. DWORD cbBuffer;
  109. HKEY hKey;
  110. *szFilePath = TEXT('\0');
  111. //
  112. // If file has not been opened yet - try to do it now
  113. // Nb: Speed is not critical here, because it is unlikely to have threads
  114. // competing, so we use not vey efficient locking
  115. EventLogSync.Lock();
  116. if ( 0 == lTotalLoggers && ( hEventLogFile == INVALID_HANDLE_VALUE)) {
  117. //
  118. // Nobody logging yet - open file
  119. //
  120. lstrcpy(szKeyName,REGSTR_PATH_STICONTROL_A);
  121. cbBuffer = sizeof(szFilePath);
  122. m_ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  123. szKeyName,
  124. 0,
  125. KEY_ALL_ACCESS,
  126. &hKey);
  127. if ( m_ErrorCode == NO_ERROR) {
  128. //
  129. // Read the value into buffer
  130. //
  131. *szFilePath = TEXT('\0');
  132. m_ErrorCode = RegQueryValueEx( hKey,
  133. REGSTR_VAL_EVENT_LOG_DIRECTORY_A,
  134. NULL,
  135. NULL,
  136. (LPBYTE) szFilePath,
  137. &cbBuffer);
  138. RegCloseKey( hKey);
  139. }
  140. // If we did not get log file directory - use system
  141. if ((NOERROR != m_ErrorCode) || !*szFilePath ) {
  142. m_ErrorCode = GetWindowsDirectory(szFilePath,sizeof(szFilePath));
  143. }
  144. if (*szFilePath ) {
  145. lstrcat(szFilePath,PSZ_EVENT_LOG_FILE__A);
  146. hEventLogFile = CreateFile(szFilePath,
  147. GENERIC_WRITE,
  148. FILE_SHARE_WRITE | FILE_SHARE_READ,
  149. NULL, // security attributes
  150. OPEN_ALWAYS,
  151. FILE_ATTRIBUTE_NORMAL,
  152. NULL); // template file handle
  153. if ( hEventLogFile != INVALID_HANDLE_VALUE) {
  154. // set the file pointer at the end of the file (append mode)
  155. if ( SetFilePointer( hEventLogFile, 0, NULL, FILE_END)
  156. == (DWORD) -1L) {
  157. hEventLogFile = INVALID_HANDLE_VALUE;
  158. CloseHandle(hEventLogFile);
  159. }
  160. }
  161. } /* endif ValidPath */
  162. } /* endif no loggers */
  163. InterlockedIncrement(&lTotalLoggers);
  164. EventLogSync.Unlock();
  165. if( hEventLogFile != INVALID_HANDLE_VALUE) {
  166. //
  167. // If log file successfully opened - register event message source file.
  168. // On Win9x registration simply means locating module handle for DLL , where we will
  169. // load messages from
  170. //
  171. lstrcpy(szKeyName,PSZ_EVENTLOG_REG_ENTRY);
  172. lstrcat(szKeyName,lpszSource);
  173. m_ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  174. szKeyName,
  175. 0,
  176. KEY_ALL_ACCESS,
  177. &hKey);
  178. if ( m_ErrorCode == NO_ERROR) {
  179. //
  180. // Read the value into buffer
  181. //
  182. cbBuffer = sizeof(szFilePath);
  183. *szFilePath = TEXT('\0');
  184. m_ErrorCode = RegQueryValueEx( hKey,
  185. PSZ_PARAMETERS_REG_ENTRY,
  186. NULL,
  187. NULL,
  188. (LPBYTE) szFilePath,
  189. &cbBuffer);
  190. RegCloseKey( hKey);
  191. if ((NOERROR == m_ErrorCode) && (*szFilePath)) {
  192. m_hEventSource = GetModuleHandle(szFilePath);
  193. //ASSERT( m_hEventSource != NULL);
  194. }
  195. }
  196. if (NO_ERROR == m_ErrorCode) {
  197. }
  198. else {
  199. //
  200. // An Error in initializing the event log.
  201. //
  202. }
  203. }
  204. else {
  205. //
  206. // An Error in initializing the event log.
  207. //
  208. m_ErrorCode = GetLastError();
  209. DPRINTF(DM_ERROR,"Could not create log file (%s) ( Error %lu)\n",
  210. szFilePath,
  211. m_ErrorCode);
  212. }
  213. m_ErrorCode = NO_ERROR;
  214. #endif // WINNT
  215. } /* EVENT_LOG::EVENT_LOG() */
  216. EVENT_LOG::~EVENT_LOG( VOID)
  217. /*++
  218. Description:
  219. Destructor function for given EVENT_LOG object.
  220. Terminates event logging functions and closes
  221. event log handle
  222. --*/
  223. {
  224. #ifdef WINNT
  225. //
  226. // If there is a valid Events handle, deregister it
  227. //
  228. if ( m_hEventSource != NULL) {
  229. BOOL fSuccess;
  230. fSuccess = DeregisterEventSource( m_hEventSource);
  231. if ( !fSuccess) {
  232. //
  233. // An Error in DeRegistering
  234. //
  235. m_ErrorCode = GetLastError();
  236. DPRINTF( DM_ERROR, TEXT("Termination of EventLog for %s failed.error %lu\n"),m_lpszSource,m_ErrorCode);
  237. }
  238. //
  239. // Reset the handle's value. Just as a precaution
  240. //
  241. m_hEventSource = NULL;
  242. }
  243. #else
  244. TAKE_MUTEX_OBJ t(EventLogSync);
  245. InterlockedDecrement(&lTotalLoggers);
  246. if ( 0 == lTotalLoggers ) {
  247. if (hEventLogFile != INVALID_HANDLE_VALUE) {
  248. FlushFileBuffers( hEventLogFile);
  249. CloseHandle(hEventLogFile);
  250. hEventLogFile = INVALID_HANDLE_VALUE;
  251. }
  252. }
  253. #endif
  254. } /* EVENT_LOG::~EVENT_LOG() */
  255. VOID
  256. EVENT_LOG::LogEvent(
  257. IN DWORD idMessage,
  258. IN WORD nSubStrings,
  259. IN const CHAR * rgpszSubStrings[],
  260. IN DWORD errCode)
  261. /*++
  262. Description:
  263. Log an event to the event logger
  264. Arguments:
  265. idMessage Identifies the event message
  266. nSubStrings Number of substrings to include in
  267. this message. (Maybe 0)
  268. rgpszSubStrings array of substrings included in the message
  269. (Maybe NULL if nSubStrings == 0)
  270. errCode An error code from Win32 or NT_STATUS.
  271. If this is not Zero, it is considered as
  272. "raw" data to be included in message
  273. Returns:
  274. None
  275. --*/
  276. {
  277. WORD wType; // Type of Event to be logged
  278. //
  279. // Find type of message for the event log
  280. //
  281. if ( NT_INFORMATION( idMessage)) {
  282. wType = EVENTLOG_INFORMATION_TYPE;
  283. } else
  284. if ( NT_WARNING( idMessage)) {
  285. wType = EVENTLOG_WARNING_TYPE;
  286. } else
  287. if ( NT_ERROR( idMessage)) {
  288. wType = EVENTLOG_ERROR_TYPE;
  289. } else {
  290. wType = EVENTLOG_ERROR_TYPE;
  291. }
  292. //
  293. // Log the event
  294. //
  295. EVENT_LOG::LogEventPrivate( idMessage,
  296. wType,
  297. nSubStrings,
  298. rgpszSubStrings,
  299. errCode);
  300. return;
  301. } /* EVENT_LOG::LogEvent() */
  302. VOID
  303. EVENT_LOG::LogEvent(
  304. IN DWORD idMessage,
  305. IN WORD nSubStrings,
  306. IN WCHAR * rgpszSubStrings[],
  307. IN DWORD errCode)
  308. /*++
  309. Description:
  310. Simple Unicode wrapper
  311. Arguments:
  312. idMessage Identifies the event message
  313. nSubStrings Number of substrings to include in
  314. this message. (Maybe 0)
  315. rgpszSubStrings array of substrings included in the message
  316. (Maybe NULL if nSubStrings == 0)
  317. errCode An error code from Win32 or WinSock or NT_STATUS.
  318. If this is not Zero, it is considered as
  319. "raw" data to be included in message
  320. Returns:
  321. None
  322. --*/
  323. {
  324. LPCSTR * apsz;
  325. DWORD cch;
  326. DWORD i;
  327. WORD nUsedSubStrings = nSubStrings;
  328. static const CHAR *szEmptyString = "";
  329. __try {
  330. apsz = new LPCSTR[nSubStrings];
  331. if ( !apsz ) {
  332. nUsedSubStrings = 0;
  333. __leave;
  334. }
  335. ZeroMemory(apsz, nSubStrings * sizeof(apsz[0]));
  336. //
  337. // Convert the array of Wide char parameters
  338. //
  339. for ( i = 0; i < nSubStrings; i++ ) {
  340. UINT cb;
  341. cb = (wcslen( rgpszSubStrings[i] ) + 1) * sizeof(CHAR);
  342. apsz[i] = new CHAR[cb];
  343. if (!apsz[i]) {
  344. //
  345. // Ouch, we can't event convert the memory for the parameters.
  346. // We'll just log the error without the params then
  347. //
  348. nUsedSubStrings = 0;
  349. __leave;
  350. }
  351. cch = WideCharToMultiByte( CP_ACP,
  352. WC_COMPOSITECHECK,
  353. rgpszSubStrings[i],
  354. -1,
  355. (LPSTR)apsz[i],
  356. cb,
  357. NULL,
  358. NULL );
  359. *((CHAR *) apsz[i] + cb) = '\0';
  360. }
  361. }
  362. __finally {
  363. //
  364. // If no substrings, then nothing to convert
  365. //
  366. LogEvent( idMessage,
  367. nUsedSubStrings,
  368. nUsedSubStrings ? apsz : &szEmptyString,
  369. errCode );
  370. if (apsz) {
  371. for ( i = 0; i < nSubStrings; i++ ) {
  372. if (apsz[i]) {
  373. delete [] (VOID *)apsz[i];
  374. }
  375. }
  376. delete [] apsz;
  377. }
  378. }
  379. }
  380. //
  381. // Private functions.
  382. //
  383. VOID
  384. EVENT_LOG::LogEventPrivate(
  385. IN DWORD idMessage,
  386. IN WORD wEventType,
  387. IN WORD nSubStrings,
  388. IN const CHAR * apszSubStrings[],
  389. IN DWORD errCode )
  390. /*++
  391. Description:
  392. Log an event to the event logger.
  393. ( Private version, includes EventType)
  394. Arguments:
  395. idMessage Identifies the event message
  396. wEventType Specifies the severety of the event
  397. (error, warning, or informational).
  398. nSubStrings Number of substrings to include in
  399. this message. (Maybe 0)
  400. apszSubStrings array of substrings included in the message
  401. (Maybe NULL if nSubStrings == 0)
  402. errCode An error code from Win32 or NT_STATUS.
  403. If this is not Zero, it is considered as
  404. "raw" data to be included in message
  405. Returns:
  406. None
  407. --*/
  408. {
  409. VOID * pRawData = NULL;
  410. DWORD cbRawData = 0;
  411. BOOL fReturn;
  412. DWORD cch,cbWritten;
  413. #ifdef WINNT
  414. BOOL fReport;
  415. ASSERT( (nSubStrings == 0) || (apszSubStrings != NULL));
  416. ASSERTSZ( (m_hEventSource != NULL),TEXT("Event log handle is not valid"));
  417. if( errCode != 0 ) {
  418. pRawData = &errCode;
  419. cbRawData = sizeof(errCode);
  420. }
  421. m_ErrorCode = NO_ERROR;
  422. fReport = ReportEvent( m_hEventSource, // hEventSource
  423. wEventType, // fwEventType
  424. 0, // fwCategory
  425. idMessage, // IDEvent
  426. NULL, // pUserSid,
  427. nSubStrings, // cStrings
  428. cbRawData, // cbData
  429. (LPCTSTR *) apszSubStrings, // plpszStrings
  430. pRawData ); // lpvData
  431. if (!fReport) {
  432. m_ErrorCode = GetLastError();
  433. }
  434. #else
  435. //CHAR szErrCodeString[20];
  436. CHAR *pchBuff = NULL;
  437. SYSTEMTIME stCurrentTime;
  438. CHAR szFmtTime[32];
  439. CHAR szFmtDate[32];
  440. CHAR szErrorText[MAX_PATH] = {'\0'};
  441. if( (hEventLogFile == INVALID_HANDLE_VALUE) ||
  442. (m_hEventSource == INVALID_HANDLE_VALUE) ) {
  443. return;
  444. }
  445. if( errCode != 0 ) {
  446. pRawData = &errCode;
  447. cbRawData = sizeof(errCode);
  448. }
  449. m_ErrorCode = NO_ERROR;
  450. //
  451. // Write name of the service, date and time, severity
  452. //
  453. *szFmtTime = *szFmtDate = '\0';
  454. GetLocalTime(&stCurrentTime);
  455. FormatStdTime( &stCurrentTime, szFmtTime, 15);
  456. FormatStdDate( &stCurrentTime, szFmtDate, 15);
  457. wsprintf(szErrorText,"[%s] %s %s :",m_lpszSource,szFmtDate,szFmtTime);
  458. WriteFile(hEventLogFile,
  459. szErrorText,
  460. lstrlen(szErrorText),
  461. &cbWritten,
  462. NULL);
  463. //
  464. // Read message and add inserts
  465. //
  466. cch = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  467. FORMAT_MESSAGE_MAX_WIDTH_MASK |
  468. FORMAT_MESSAGE_FROM_HMODULE |
  469. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  470. m_hEventSource,
  471. idMessage,
  472. 0,
  473. (LPSTR) &pchBuff,
  474. 1024,
  475. (va_list *)apszSubStrings
  476. );
  477. if (cch ) {
  478. TAKE_MUTEX_OBJ t(EventLogSync);
  479. fReturn = WriteFile(hEventLogFile,pchBuff,cch,&cbWritten,NULL);
  480. LocalFree(pchBuff);
  481. if (cbWritten) {
  482. WriteFile(hEventLogFile,"\n\r",2,&cbWritten,NULL);
  483. return ;
  484. }
  485. }
  486. m_ErrorCode = GetLastError();
  487. #endif
  488. } /* EVENT_LOG::~LogEventPrivate() */
  489. VOID
  490. WINAPI
  491. RegisterStiEventSources(
  492. VOID
  493. )
  494. /*++
  495. Description:
  496. Adds necessary registry entry when installing service
  497. Arguments:
  498. Returns:
  499. None
  500. --*/
  501. {
  502. RegEntry re(PSZ_EVENTLOG_REG_ENTRY,HKEY_LOCAL_MACHINE);
  503. re.SetValue(PSZ_PARAMETERS_REG_ENTRY,STI_IMAGE_NAME);
  504. re.SetValue(PSZ_TYPES_REG_ENTRY,7);
  505. }
  506. /********************************* End of File ***************************/