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.

650 lines
15 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. eventlog.cxx
  5. Abstract:
  6. This module defines the generic class for logging events.
  7. Author:
  8. Murali R. Krishnan (MuraliK) 28-Sept-1994
  9. Depends Upon:
  10. Internet Services Platform Library (isplat.lib)
  11. Internet Services Debugging Library (isdebug.lib)
  12. --*/
  13. #include "precomp.hxx"
  14. //
  15. // Include Headers
  16. //
  17. #define DLL_IMPLEMENTATION
  18. #define IMPLEMENTATION_EXPORT
  19. # include <isplat.h>
  20. # include <dbgutil.h>
  21. # include <eventlog.hxx>
  22. # include <string.hxx>
  23. #define EVENTLOG_KEY \
  24. "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\"
  25. #define EVENTLOG_VALUE_KEY "EventMessageFile"
  26. EVENT_LOG::EVENT_LOG(
  27. IN LPCTSTR lpszSource
  28. )
  29. /*++
  30. Description
  31. Constructor function for given event log object.
  32. Initializes event logging services.
  33. Arguments:
  34. lpszSource: Source string for the Event.
  35. Note:
  36. This is intended to be executed once only.
  37. This is not to be used for creating multiple event
  38. log handles for same given source name.
  39. But can be used for creating EVENT_LOG objects for
  40. different source names.
  41. --*/
  42. :
  43. m_ErrorCode (NO_ERROR),
  44. m_pDateTimeCache (NULL),
  45. m_hLogFile (INVALID_HANDLE_VALUE)
  46. {
  47. (VOID)IISGetPlatformType();
  48. IF_DEBUG( INIT_CLEAN) {
  49. DBGPRINTF( ( DBG_CONTEXT,
  50. " Initializing Event Log for %s[%p] fLogFile[%x]\n",
  51. lpszSource, this, TsIsWindows95()));
  52. }
  53. //
  54. // Register as an event source.
  55. //
  56. if ( TsIsWindows95() ) {
  57. m_hEventSource = RegisterEventSourceChicagoStyle(
  58. lpszSource,
  59. &m_hLogFile
  60. );
  61. } else {
  62. m_hEventSource = RegisterEventSource( NULL, lpszSource);
  63. }
  64. if ( m_hEventSource != NULL ) {
  65. //
  66. // Success!
  67. //
  68. IF_DEBUG( ERROR) {
  69. DBGPRINTF( ( DBG_CONTEXT,
  70. " Event Log for %s initialized (hEventSource=%p)\n",
  71. lpszSource,
  72. m_hEventSource));
  73. }
  74. } else {
  75. DBG_ASSERT(m_hLogFile == INVALID_HANDLE_VALUE);
  76. //
  77. // An Error in initializing the event log.
  78. //
  79. m_ErrorCode = GetLastError();
  80. DBGPRINTF( ( DBG_CONTEXT,
  81. "Could not register event source (%s) ( Error %lu)\n",
  82. lpszSource,
  83. m_ErrorCode));
  84. }
  85. return;
  86. } // EVENT_LOG::EVENT_LOG()
  87. EVENT_LOG::~EVENT_LOG(
  88. VOID
  89. )
  90. /*++
  91. Description:
  92. Destructor function for given EVENT_LOG object.
  93. Terminates event logging functions and closes
  94. event log handle
  95. --*/
  96. {
  97. IF_DEBUG( INIT_CLEAN) {
  98. DBGPRINTF( ( DBG_CONTEXT,
  99. "Terminating events logging[%p] fFile[%x]\n",
  100. this, TsIsWindows95() ));
  101. }
  102. if ( TsIsWindows95() ) {
  103. if ( m_hLogFile != INVALID_HANDLE_VALUE ) {
  104. FlushFileBuffers(m_hLogFile);
  105. DBG_REQUIRE(CloseHandle( m_hLogFile ));
  106. m_hLogFile = INVALID_HANDLE_VALUE;
  107. }
  108. if ( m_pDateTimeCache != NULL ) {
  109. delete m_pDateTimeCache;
  110. m_pDateTimeCache = NULL;
  111. }
  112. } else {
  113. //
  114. // If there is a valid Events handle, deregister it
  115. //
  116. if ( m_hEventSource != NULL) {
  117. BOOL fSuccess;
  118. fSuccess = DeregisterEventSource( m_hEventSource);
  119. if ( !fSuccess) {
  120. //
  121. // An Error in DeRegistering
  122. //
  123. m_ErrorCode = GetLastError();
  124. IF_DEBUG( INIT_CLEAN) {
  125. DBGPRINTF( ( DBG_CONTEXT,
  126. "Termination of EventLog[%p] failed."
  127. " error %lu\n",
  128. this,
  129. m_ErrorCode));
  130. }
  131. }
  132. //
  133. // Reset the handle's value. Just as a precaution
  134. //
  135. m_hEventSource = NULL;
  136. }
  137. }
  138. IF_DEBUG( API_EXIT) {
  139. DBGPRINTF( ( DBG_CONTEXT, "Terminated events log[%p]\n",this));
  140. }
  141. } /* EVENT_LOG::~EVENT_LOG() */
  142. VOID
  143. EVENT_LOG::LogEvent(
  144. IN DWORD idMessage,
  145. IN WORD nSubStrings,
  146. IN const CHAR * rgpszSubStrings[],
  147. IN DWORD errCode)
  148. /*++
  149. Description:
  150. Log an event to the event logger
  151. Arguments:
  152. idMessage Identifies the event message
  153. nSubStrings Number of substrings to include in
  154. this message. (Maybe 0)
  155. rgpszSubStrings array of substrings included in the message
  156. (Maybe NULL if nSubStrings == 0)
  157. errCode An error code from Win32 or WinSock or NT_STATUS.
  158. If this is not Zero, it is considered as
  159. "raw" data to be included in message
  160. Returns:
  161. None
  162. --*/
  163. {
  164. WORD wType; // Type of Event to be logged
  165. //
  166. // Find type of message for the event log
  167. //
  168. IF_DEBUG( API_ENTRY) {
  169. DWORD i;
  170. DBGPRINTF( ( DBG_CONTEXT,
  171. "reporting event %08lX, Error Code = %lu\n",
  172. idMessage,
  173. errCode ));
  174. for( i = 0 ; i < nSubStrings ; i++ ) {
  175. DBGPRINTF(( DBG_CONTEXT,
  176. " substring[%lu] = %s\n",
  177. i,
  178. rgpszSubStrings[i] ));
  179. }
  180. }
  181. if ( NT_INFORMATION( idMessage)) {
  182. wType = EVENTLOG_INFORMATION_TYPE;
  183. } else {
  184. if ( NT_WARNING( idMessage)) {
  185. wType = EVENTLOG_WARNING_TYPE;
  186. } else {
  187. wType = EVENTLOG_ERROR_TYPE;
  188. DBG_ASSERT(NT_ERROR( idMessage));
  189. }
  190. }
  191. //
  192. // Log the event
  193. //
  194. EVENT_LOG::LogEventPrivate( idMessage,
  195. wType,
  196. nSubStrings,
  197. rgpszSubStrings,
  198. errCode);
  199. return;
  200. } /* EVENT_LOG::LogEvent() */
  201. //
  202. // Private functions.
  203. //
  204. VOID
  205. EVENT_LOG::LogEventPrivate(
  206. IN DWORD idMessage,
  207. IN WORD wEventType,
  208. IN WORD nSubStrings,
  209. IN const CHAR * apszSubStrings[],
  210. IN DWORD errCode
  211. )
  212. /*++
  213. Description:
  214. Log an event to the event logger.
  215. ( Private version, includes EventType)
  216. Arguments:
  217. idMessage Identifies the event message
  218. wEventType Specifies the severety of the event
  219. (error, warning, or informational).
  220. nSubStrings Number of substrings to include in
  221. this message. (Maybe 0)
  222. apszSubStrings array of substrings included in the message
  223. (Maybe NULL if nSubStrings == 0)
  224. errCode An error code from Win32 or WinSock or NT_STATUS.
  225. If this is not Zero, it is considered as
  226. "raw" data to be included in message
  227. Returns:
  228. None
  229. --*/
  230. {
  231. VOID * pRawData = NULL;
  232. DWORD cbRawData = 0;
  233. BOOL fReport;
  234. DWORD dwErr;
  235. if ( m_hEventSource == NULL ) {
  236. IF_DEBUG(ERROR) {
  237. DBGPRINTF((DBG_CONTEXT,"Attempt to log with no event source\n"));
  238. }
  239. return;
  240. }
  241. ASSERT( (nSubStrings == 0) || (apszSubStrings != NULL));
  242. if( errCode != 0 ) {
  243. pRawData = &errCode;
  244. cbRawData = sizeof(errCode);
  245. }
  246. m_ErrorCode = NO_ERROR;
  247. dwErr = GetLastError();
  248. if ( TsIsWindows95() ) {
  249. fReport = ReportEventChicagoStyle(
  250. m_hEventSource,
  251. m_hLogFile,
  252. idMessage,
  253. apszSubStrings,
  254. errCode
  255. );
  256. } else {
  257. fReport = ReportEvent(
  258. m_hEventSource, // hEventSource
  259. wEventType, // fwEventType
  260. 0, // fwCategory
  261. idMessage, // IDEvent
  262. NULL, // pUserSid,
  263. nSubStrings, // cStrings
  264. cbRawData, // cbData
  265. (LPCTSTR *) apszSubStrings, // plpszStrings
  266. pRawData ); // lpvData
  267. #ifdef DBG
  268. //
  269. // Output the event log to the debugger
  270. //
  271. CHAR buffer[MAX_PATH+1];
  272. PCHAR pBuffer = buffer;
  273. ::FormatMessageA(FORMAT_MESSAGE_MAX_WIDTH_MASK |
  274. FORMAT_MESSAGE_FROM_HMODULE |
  275. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  276. m_hEventSource,
  277. idMessage,
  278. 0,
  279. (LPSTR)pBuffer,
  280. (DWORD)sizeof(buffer),
  281. (va_list*)apszSubStrings
  282. );
  283. DBGPRINTF((DBG_CONTEXT,"Reporting EVENT_LOG Event - %s\n", buffer));
  284. #endif
  285. }
  286. if ( !fReport ) {
  287. IF_DEBUG( ERROR) {
  288. m_ErrorCode = GetLastError();
  289. DBGPRINTF(( DBG_CONTEXT,
  290. "Cannot report event for %p, error %lu\n",
  291. this,
  292. m_ErrorCode));
  293. }
  294. }
  295. else {
  296. SetLastError( dwErr );
  297. }
  298. } // EVENT_LOG::LogEventPrivate()
  299. HANDLE
  300. EVENT_LOG::RegisterEventSourceChicagoStyle(
  301. IN LPCSTR lpszSource,
  302. IN PHANDLE hFile
  303. )
  304. /*++
  305. Description:
  306. Register event source in win95
  307. Arguments:
  308. lpszSource - name of event source
  309. hFile - on return, contains handle to log file
  310. Returns:
  311. if successful, Handle to event source
  312. NULL, otherwise
  313. --*/
  314. {
  315. HANDLE hSource = NULL;
  316. CHAR szPath[MAX_PATH+1];
  317. STR regKey;
  318. DWORD len;
  319. DWORD err = NO_ERROR;
  320. HKEY hKey;
  321. HANDLE hEventFile = INVALID_HANDLE_VALUE;
  322. //
  323. // Initialize the cache
  324. //
  325. m_pDateTimeCache = new ASCLOG_DATETIME_CACHE(); //log format
  326. if ( m_pDateTimeCache == NULL ) {
  327. err = GetLastError();
  328. DBGPRINTF((DBG_CONTEXT,
  329. "Cannot allocate datetime cache[%d]\n", err));
  330. goto exit;
  331. }
  332. //
  333. // Contruct the log file name
  334. //
  335. len = GetWindowsDirectory(szPath, sizeof(szPath));
  336. if ( len == 0 ) {
  337. DBGPRINTF((DBG_CONTEXT,"GetWindowsDirectory returns 0\n"));
  338. goto exit;
  339. }
  340. DBG_ASSERT(len <= MAX_PATH);
  341. strcat(szPath, "\\");
  342. strcat(szPath, lpszSource);
  343. strcat(szPath, ".event.log");
  344. IF_DEBUG( INIT_CLEAN) {
  345. DBGPRINTF((DBG_CONTEXT,"Event log file set to %s\n", szPath));
  346. }
  347. //
  348. // Open the file
  349. //
  350. hEventFile = CreateFile(
  351. szPath,
  352. GENERIC_WRITE,
  353. FILE_SHARE_READ | FILE_SHARE_WRITE,
  354. NULL,
  355. OPEN_ALWAYS,
  356. FILE_ATTRIBUTE_NORMAL,
  357. NULL
  358. );
  359. if ( hEventFile == INVALID_HANDLE_VALUE ) {
  360. err = GetLastError();
  361. goto exit;
  362. }
  363. //
  364. // Move to end of file
  365. //
  366. if ( SetFilePointer( hEventFile, 0, NULL, FILE_END ) == (DWORD)-1 ) {
  367. err = GetLastError();
  368. goto exit;
  369. }
  370. //
  371. // If log file successfully opened - register event message source file.
  372. // On Win9x registration simply means locating module handle for DLL,
  373. // where we will load messages from.
  374. //
  375. regKey.Copy(EVENTLOG_KEY);
  376. regKey.Append(lpszSource);
  377. err = RegOpenKeyEx(
  378. HKEY_LOCAL_MACHINE,
  379. regKey.QueryStr(),
  380. 0,
  381. KEY_ALL_ACCESS,
  382. &hKey);
  383. if ( err == NO_ERROR) {
  384. DWORD cbBuffer;
  385. cbBuffer = sizeof(szPath);
  386. szPath[0] = '\0';
  387. err = RegQueryValueEx( hKey,
  388. EVENTLOG_VALUE_KEY,
  389. NULL,
  390. NULL,
  391. (LPBYTE) szPath,
  392. &cbBuffer);
  393. RegCloseKey( hKey);
  394. if ( err == NO_ERROR ) {
  395. hSource = GetModuleHandle(szPath);
  396. if ( hSource == NULL ) {
  397. err = GetLastError();
  398. DBGPRINTF((DBG_CONTEXT,"GetModuleHandle[%s] returns %d\n",
  399. szPath, err));
  400. }
  401. } else {
  402. DBGPRINTF((DBG_CONTEXT,
  403. "Cannot find value %s. Err = %d\n",
  404. EVENTLOG_VALUE_KEY, err ));
  405. }
  406. } else {
  407. DBGPRINTF((DBG_CONTEXT,
  408. "Cannot open key %s. Err = %d\n",
  409. regKey.QueryStr(), err ));
  410. }
  411. exit:
  412. if ( (err != NO_ERROR) || (hSource == NULL) ) {
  413. if ( hEventFile != INVALID_HANDLE_VALUE ) {
  414. CloseHandle( hEventFile );
  415. hEventFile = INVALID_HANDLE_VALUE;
  416. }
  417. hSource = NULL;
  418. SetLastError(err);
  419. }
  420. *hFile = hEventFile;
  421. return(hSource);
  422. } // RegisterEventSourceChicagoStyle()
  423. BOOL
  424. EVENT_LOG::ReportEventChicagoStyle(
  425. IN HANDLE hEventSource,
  426. IN HANDLE hLogFile,
  427. IN DWORD idMessage,
  428. IN LPCSTR * apszSubStrings,
  429. IN DWORD dwErrorCode
  430. )
  431. {
  432. SYSTEMTIME st;
  433. DWORD cch;
  434. DWORD nDate;
  435. CHAR buffer[MAX_PATH+1];
  436. PCHAR pBuffer = buffer;
  437. BOOL fReturn = FALSE;
  438. GetLocalTime( &st );
  439. nDate = m_pDateTimeCache->GetFormattedDateTime(&st, pBuffer);
  440. pBuffer += nDate;
  441. //
  442. // Read message and add inserts
  443. //
  444. cch = ::FormatMessageA(FORMAT_MESSAGE_MAX_WIDTH_MASK |
  445. FORMAT_MESSAGE_FROM_HMODULE |
  446. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  447. hEventSource,
  448. idMessage,
  449. 0,
  450. (LPSTR)pBuffer,
  451. (DWORD)(sizeof(buffer) - nDate),
  452. (va_list*)apszSubStrings
  453. );
  454. if (cch != 0) {
  455. DWORD nBytes = 0;
  456. DBGPRINTF((DBG_CONTEXT,"Reporting EVENT_LOG Event - %s\n", buffer));
  457. cch += nDate;
  458. fReturn = WriteFile(
  459. hLogFile,
  460. buffer,
  461. cch,
  462. &nBytes,
  463. NULL);
  464. if (nBytes != 0) {
  465. DBG_ASSERT(cch == nBytes);
  466. cch = wsprintf(buffer,"[%x]\r\n",dwErrorCode);
  467. fReturn = WriteFile(hLogFile,buffer,cch,&nBytes,NULL);
  468. }
  469. }
  470. return(fReturn);
  471. } // ReportEventChicagoStyle()