Leaked source code of windows server 2003
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.

973 lines
22 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. eventlog.c
  5. Abstract:
  6. This module provides common eventlog services for the cluster service
  7. Author:
  8. John Vert (jvert) 9/13/1996
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusrtlp.h"
  13. HANDLE LocalEventLog=NULL;
  14. CRITICAL_SECTION EventLogLock;
  15. //
  16. // [GN] June 19/1999: added Async EventReporting
  17. //
  18. // Use ClRtlEventLogSetWorkQueue to set a queue
  19. // for async event reporting. If it the queue is not set,
  20. // event reporting is synchronous as it used to be before
  21. //
  22. static CLRTL_WORK_ITEM EvtReporterWorkItem;
  23. static PCLRTL_WORK_QUEUE EvtReporterWorkQueue;
  24. #if 0
  25. //
  26. // additional data is stored after this structure. lpStrings is the base of an
  27. // array that will continue. Following the strings is the area pointed by
  28. // lpRawData if there is any. Following that are the strings themselves. They
  29. // are pointed to by the entries in lpStrings.
  30. //
  31. +------------------+
  32. | EVENT_LOG_PACKET |
  33. +------------------+
  34. | lpStrings[0] |
  35. | lpStrings[1] |
  36. | lpStrings[2] |
  37. | ... |
  38. +------------------+
  39. | lpRawData area |
  40. | (maybe missing) |
  41. | |
  42. +------------------+
  43. | string0 |
  44. | string1 |
  45. | ... |
  46. +------------------+
  47. #endif
  48. typedef struct _EVENT_LOG_PACKET {
  49. WORD wType;
  50. WORD wCategory;
  51. DWORD dwEventID;
  52. WORD wNumStrings;
  53. DWORD dwDataSize;
  54. LPVOID lpRawData;
  55. LPWSTR lpStrings[0];
  56. } *PEVENT_LOG_PACKET, EVENT_LOG_PACKET;
  57. VOID
  58. ClRtlEventLogSetWorkQueue(
  59. PCLRTL_WORK_QUEUE WorkQueue
  60. )
  61. {
  62. EnterCriticalSection( &EventLogLock );
  63. EvtReporterWorkQueue = WorkQueue;
  64. LeaveCriticalSection( &EventLogLock );
  65. }
  66. VOID
  67. EvtReporter(
  68. IN PCLRTL_WORK_ITEM WorkItem,
  69. IN DWORD Status,
  70. IN DWORD BytesTransferred,
  71. IN ULONG_PTR IoContext
  72. )
  73. /*++
  74. Routine Description:
  75. Reports queued event via advapi32!ReportEvent
  76. Arguments:
  77. IoContext == EVENT_LOG_PACKET
  78. Return Value:
  79. None
  80. --*/
  81. {
  82. PEVENT_LOG_PACKET data = (PEVENT_LOG_PACKET)IoContext;
  83. ReportEventW(LocalEventLog,
  84. data->wType,
  85. data->wCategory,
  86. data->dwEventID,
  87. NULL,
  88. data->wNumStrings,
  89. data->dwDataSize,
  90. data->lpStrings,
  91. data->lpRawData);
  92. LocalFree(data);
  93. }
  94. VOID
  95. ClRtlEventLogInit(
  96. VOID
  97. )
  98. /*++
  99. Routine Description:
  100. initializes the event log
  101. Arguments:
  102. None
  103. Return Value:
  104. None
  105. --*/
  106. {
  107. InitializeCriticalSection(&EventLogLock);
  108. EvtReporterWorkQueue = 0;
  109. ClRtlInitializeWorkItem(
  110. &EvtReporterWorkItem,
  111. EvtReporter,
  112. 0
  113. );
  114. }
  115. VOID
  116. ClRtlEventLogCleanup(
  117. VOID
  118. )
  119. {
  120. DeleteCriticalSection( &EventLogLock );
  121. }
  122. PEVENT_LOG_PACKET
  123. ClRtlpBuildEventPacket(
  124. WORD wType,
  125. WORD wCategory,
  126. DWORD dwEventID,
  127. WORD wNumStrings,
  128. DWORD dwDataSize,
  129. LPCWSTR *lpStrings,
  130. LPVOID lpRawData
  131. )
  132. {
  133. PEVENT_LOG_PACKET data = 0;
  134. DWORD Count;
  135. UINT i;
  136. LPBYTE ptr;
  137. Count = sizeof(EVENT_LOG_PACKET) +
  138. dwDataSize +
  139. wNumStrings * (sizeof(LPCWSTR) + sizeof(UNICODE_NULL));
  140. for (i = 0; i < wNumStrings; ++i) {
  141. int len = lstrlenW( lpStrings[i] );
  142. Count += len * sizeof(WCHAR); // (null is already accounted for)
  143. }
  144. data = LocalAlloc(LMEM_FIXED, Count);
  145. if (!data) {
  146. return 0;
  147. }
  148. data->wType = wType;
  149. data->wCategory = wCategory;
  150. data->dwEventID = dwEventID;
  151. data->wNumStrings = wNumStrings;
  152. data->dwDataSize = dwDataSize;
  153. data->lpRawData = &data->lpStrings[wNumStrings];
  154. // lpStrings will be filled later
  155. if (dwDataSize) {
  156. CopyMemory(data->lpRawData, lpRawData, dwDataSize);
  157. }
  158. ptr = (LPBYTE)data->lpRawData + dwDataSize;
  159. for (i = 0; i < wNumStrings; ++i) {
  160. int nBytes = (lstrlenW( lpStrings[i] ) + 1) * sizeof(WCHAR);
  161. CopyMemory(ptr, lpStrings[i], nBytes);
  162. data->lpStrings[i] = (LPWSTR)ptr;
  163. ptr += nBytes;
  164. }
  165. CL_ASSERT(ptr <= (LPBYTE)data + Count);
  166. return data;
  167. }
  168. VOID
  169. ClRtlpReportEvent(
  170. WORD wType,
  171. WORD wCategory,
  172. DWORD dwEventID,
  173. WORD wNumStrings,
  174. DWORD dwDataSize,
  175. LPCWSTR *lpStrings,
  176. LPVOID lpRawData
  177. )
  178. /*++
  179. Routine Description:
  180. Common routine for reporting an event to the event log. Opens a handle
  181. to the event log if necessary.
  182. Arguments:
  183. Identical arguments to ReportEventW
  184. Return Value:
  185. None
  186. --*/
  187. {
  188. BOOL Success = FALSE;
  189. DWORD Status;
  190. //
  191. // If the event log hasn't been opened, try and open it now.
  192. //
  193. if (LocalEventLog == NULL) {
  194. EnterCriticalSection(&EventLogLock);
  195. if (LocalEventLog == NULL) {
  196. LocalEventLog = RegisterEventSource(NULL, L"ClusSvc");
  197. }
  198. LeaveCriticalSection(&EventLogLock);
  199. if (LocalEventLog == NULL) {
  200. Status = GetLastError();
  201. return;
  202. }
  203. }
  204. if (EvtReporterWorkQueue) {
  205. PEVENT_LOG_PACKET data =
  206. ClRtlpBuildEventPacket(wType,
  207. wCategory,
  208. dwEventID,
  209. wNumStrings,
  210. dwDataSize,
  211. lpStrings,
  212. lpRawData);
  213. if (data) {
  214. EnterCriticalSection( &EventLogLock );
  215. if (EvtReporterWorkQueue) {
  216. Status = ClRtlPostItemWorkQueue(
  217. EvtReporterWorkQueue,
  218. &EvtReporterWorkItem,
  219. 0,
  220. (ULONG_PTR)data
  221. );
  222. if (Status == ERROR_SUCCESS) {
  223. // worker will free data //
  224. data = NULL;
  225. Success = TRUE;
  226. }
  227. }
  228. LeaveCriticalSection( &EventLogLock );
  229. LocalFree( data ); // free(0) is OK
  230. if (Success) {
  231. return;
  232. }
  233. }
  234. }
  235. Success = ReportEventW(LocalEventLog,
  236. wType,
  237. wCategory,
  238. dwEventID,
  239. NULL,
  240. wNumStrings,
  241. dwDataSize,
  242. lpStrings,
  243. lpRawData);
  244. }
  245. VOID
  246. ClusterLogEvent0(
  247. IN DWORD LogLevel,
  248. IN DWORD LogModule,
  249. IN LPSTR FileName,
  250. IN DWORD LineNumber,
  251. IN DWORD MessageId,
  252. IN DWORD dwByteCount,
  253. IN PVOID lpBytes
  254. )
  255. /*++
  256. Routine Description:
  257. Logs an event to the event log
  258. Arguments:
  259. LogLevel - Supplies the logging level, one of
  260. LOG_CRITICAL 1
  261. LOG_UNUSUAL 2
  262. LOG_NOISE 3
  263. LogModule - Supplies the module ID.
  264. FileName - Supplies the filename of the caller
  265. LineNumber - Supplies the line number of the caller
  266. MessageId - Supplies the message ID to be logged.
  267. dwByteCount - Supplies the number of error-specific bytes to log. If this
  268. is zero, lpBytes is ignored.
  269. lpBytes - Supplies the error-specific bytes to log.
  270. Return Value:
  271. None.
  272. --*/
  273. {
  274. BOOL Success;
  275. DWORD Status;
  276. WORD wType;
  277. switch (LogLevel) {
  278. case LOG_CRITICAL:
  279. wType = EVENTLOG_ERROR_TYPE;
  280. break;
  281. case LOG_UNUSUAL:
  282. wType = EVENTLOG_WARNING_TYPE;
  283. break;
  284. case LOG_NOISE:
  285. wType = EVENTLOG_INFORMATION_TYPE;
  286. break;
  287. default:
  288. // Assert if invalid so that in retail we don't bring down the entire process.
  289. //
  290. CL_ASSERT( 0 );
  291. // Fall through to normal logging...
  292. wType = EVENTLOG_ERROR_TYPE;
  293. }
  294. ClRtlpReportEvent(wType,
  295. (WORD)LogModule,
  296. MessageId,
  297. 0,
  298. dwByteCount,
  299. NULL,
  300. lpBytes);
  301. }
  302. VOID
  303. ClusterLogEvent1(
  304. IN DWORD LogLevel,
  305. IN DWORD LogModule,
  306. IN LPSTR FileName,
  307. IN DWORD LineNumber,
  308. IN DWORD MessageId,
  309. IN DWORD dwByteCount,
  310. IN PVOID lpBytes,
  311. IN LPCWSTR Arg1
  312. )
  313. /*++
  314. Routine Description:
  315. Logs an event to the event log
  316. Arguments:
  317. LogLevel - Supplies the logging level, one of
  318. LOG_CRITICAL 1
  319. LOG_UNUSUAL 2
  320. LOG_NOISE 3
  321. LogModule - Supplies the module ID.
  322. FileName - Supplies the filename of the caller
  323. LineNumber - Supplies the line number of the caller
  324. MessageId - Supplies the message ID to be logged.
  325. dwByteCount - Supplies the number of error-specific bytes to log. If this
  326. is zero, lpBytes is ignored.
  327. lpBytes - Supplies the error-specific bytes to log.
  328. Arg1 - Supplies an insertion string
  329. Return Value:
  330. None.
  331. --*/
  332. {
  333. BOOL Success;
  334. DWORD Status;
  335. WORD wType;
  336. switch (LogLevel) {
  337. case LOG_CRITICAL:
  338. wType = EVENTLOG_ERROR_TYPE;
  339. break;
  340. case LOG_UNUSUAL:
  341. wType = EVENTLOG_WARNING_TYPE;
  342. break;
  343. case LOG_NOISE:
  344. wType = EVENTLOG_INFORMATION_TYPE;
  345. break;
  346. default:
  347. // Assert if invalid so that in retail we don't bring down the entire process.
  348. //
  349. CL_ASSERT( 0 );
  350. // Fall through to normal logging...
  351. wType = EVENTLOG_ERROR_TYPE;
  352. }
  353. ClRtlpReportEvent(wType,
  354. (WORD)LogModule,
  355. MessageId,
  356. 1,
  357. dwByteCount,
  358. &Arg1,
  359. lpBytes);
  360. }
  361. VOID
  362. ClusterLogEvent2(
  363. IN DWORD LogLevel,
  364. IN DWORD LogModule,
  365. IN LPSTR FileName,
  366. IN DWORD LineNumber,
  367. IN DWORD MessageId,
  368. IN DWORD dwByteCount,
  369. IN PVOID lpBytes,
  370. IN LPCWSTR Arg1,
  371. IN LPCWSTR Arg2
  372. )
  373. /*++
  374. Routine Description:
  375. Logs an event to the event log
  376. Arguments:
  377. LogLevel - Supplies the logging level, one of
  378. LOG_CRITICAL 1
  379. LOG_UNUSUAL 2
  380. LOG_NOISE 3
  381. LogModule - Supplies the module ID.
  382. FileName - Supplies the filename of the caller
  383. LineNumber - Supplies the line number of the caller
  384. MessageId - Supplies the message ID to be logged.
  385. dwByteCount - Supplies the number of error-specific bytes to log. If this
  386. is zero, lpBytes is ignored.
  387. lpBytes - Supplies the error-specific bytes to log.
  388. Arg1 - Supplies the first insertion string
  389. Arg2 - Supplies the second insertion string
  390. Return Value:
  391. None.
  392. --*/
  393. {
  394. BOOL Success;
  395. DWORD Status;
  396. WORD wType;
  397. LPCWSTR ArgArray[2];
  398. switch (LogLevel) {
  399. case LOG_CRITICAL:
  400. wType = EVENTLOG_ERROR_TYPE;
  401. break;
  402. case LOG_UNUSUAL:
  403. wType = EVENTLOG_WARNING_TYPE;
  404. break;
  405. case LOG_NOISE:
  406. wType = EVENTLOG_INFORMATION_TYPE;
  407. break;
  408. default:
  409. // Assert if invalid so that in retail we don't bring down the entire process.
  410. //
  411. CL_ASSERT( 0 );
  412. // Fall through to normal logging...
  413. wType = EVENTLOG_ERROR_TYPE;
  414. }
  415. ArgArray[0] = Arg1;
  416. ArgArray[1] = Arg2;
  417. ClRtlpReportEvent(wType,
  418. (WORD)LogModule,
  419. MessageId,
  420. 2,
  421. dwByteCount,
  422. ArgArray,
  423. lpBytes);
  424. }
  425. VOID
  426. ClusterLogEvent3(
  427. IN DWORD LogLevel,
  428. IN DWORD LogModule,
  429. IN LPSTR FileName,
  430. IN DWORD LineNumber,
  431. IN DWORD MessageId,
  432. IN DWORD dwByteCount,
  433. IN PVOID lpBytes,
  434. IN LPCWSTR Arg1,
  435. IN LPCWSTR Arg2,
  436. IN LPCWSTR Arg3
  437. )
  438. /*++
  439. Routine Description:
  440. Logs an event to the event log
  441. Arguments:
  442. LogLevel - Supplies the logging level, one of
  443. LOG_CRITICAL 1
  444. LOG_UNUSUAL 2
  445. LOG_NOISE 3
  446. LogModule - Supplies the module ID.
  447. FileName - Supplies the filename of the caller
  448. LineNumber - Supplies the line number of the caller
  449. MessageId - Supplies the message ID to be logged.
  450. dwByteCount - Supplies the number of error-specific bytes to log. If this
  451. is zero, lpBytes is ignored.
  452. lpBytes - Supplies the error-specific bytes to log.
  453. Arg1 - Supplies the first insertion string
  454. Arg2 - Supplies the second insertion string
  455. Arg3 - Supplies the third insertion string
  456. Return Value:
  457. None.
  458. --*/
  459. {
  460. BOOL Success;
  461. DWORD Status;
  462. WORD wType;
  463. LPCWSTR ArgArray[3];
  464. switch (LogLevel) {
  465. case LOG_CRITICAL:
  466. wType = EVENTLOG_ERROR_TYPE;
  467. break;
  468. case LOG_UNUSUAL:
  469. wType = EVENTLOG_WARNING_TYPE;
  470. break;
  471. case LOG_NOISE:
  472. wType = EVENTLOG_INFORMATION_TYPE;
  473. break;
  474. default:
  475. // Assert if invalid so that in retail we don't bring down the entire process.
  476. //
  477. CL_ASSERT( 0 );
  478. // Fall through to normal logging...
  479. wType = EVENTLOG_ERROR_TYPE;
  480. }
  481. ArgArray[0] = Arg1;
  482. ArgArray[1] = Arg2;
  483. ArgArray[2] = Arg3;
  484. ClRtlpReportEvent(wType,
  485. (WORD)LogModule,
  486. MessageId,
  487. 3,
  488. dwByteCount,
  489. ArgArray,
  490. lpBytes);
  491. }
  492. VOID
  493. ClusterLogEvent4(
  494. IN DWORD LogLevel,
  495. IN DWORD LogModule,
  496. IN LPSTR FileName,
  497. IN DWORD LineNumber,
  498. IN DWORD MessageId,
  499. IN DWORD dwByteCount,
  500. IN PVOID lpBytes,
  501. IN LPCWSTR Arg1,
  502. IN LPCWSTR Arg2,
  503. IN LPCWSTR Arg3,
  504. IN LPCWSTR Arg4
  505. )
  506. /*++
  507. Routine Description:
  508. Logs an event to the event log
  509. Arguments:
  510. LogLevel - Supplies the logging level, one of
  511. LOG_CRITICAL 1
  512. LOG_UNUSUAL 2
  513. LOG_NOISE 3
  514. LogModule - Supplies the module ID.
  515. FileName - Supplies the filename of the caller
  516. LineNumber - Supplies the line number of the caller
  517. MessageId - Supplies the message ID to be logged.
  518. dwByteCount - Supplies the number of error-specific bytes to log. If this
  519. is zero, lpBytes is ignored.
  520. lpBytes - Supplies the error-specific bytes to log.
  521. Arg1 - Supplies the first insertion string
  522. Arg2 - Supplies the second insertion string
  523. Arg3 - Supplies the third insertion string
  524. Arg4 - Supplies the fourth insertion string
  525. Return Value:
  526. None.
  527. --*/
  528. {
  529. BOOL Success;
  530. DWORD Status;
  531. WORD wType;
  532. LPCWSTR ArgArray[4];
  533. switch (LogLevel) {
  534. case LOG_CRITICAL:
  535. wType = EVENTLOG_ERROR_TYPE;
  536. break;
  537. case LOG_UNUSUAL:
  538. wType = EVENTLOG_WARNING_TYPE;
  539. break;
  540. case LOG_NOISE:
  541. wType = EVENTLOG_INFORMATION_TYPE;
  542. break;
  543. default:
  544. // Assert if invalid so that in retail we don't bring down the entire process.
  545. //
  546. CL_ASSERT( 0 );
  547. // Fall through to normal logging...
  548. wType = EVENTLOG_ERROR_TYPE;
  549. }
  550. ArgArray[0] = Arg1;
  551. ArgArray[1] = Arg2;
  552. ArgArray[2] = Arg3;
  553. ArgArray[3] = Arg4;
  554. ClRtlpReportEvent(wType,
  555. (WORD)LogModule,
  556. MessageId,
  557. 4,
  558. dwByteCount,
  559. ArgArray,
  560. lpBytes);
  561. }
  562. VOID
  563. ClusterCommonLogError(
  564. IN ULONG MessageId,
  565. IN ULONG LogModule,
  566. IN ULONG Line,
  567. IN LPSTR File,
  568. IN ULONG ErrCode
  569. )
  570. /*++
  571. Routine Description:
  572. Logs an error to the eventlog
  573. Arguments:
  574. MessageId - Supplies the message ID to use.
  575. LogModule - Supplies the module.
  576. Line - Supplies the line number of the caller.
  577. File - Supplies the filename of the caller.
  578. ErrCode - Supplies the specific error code.
  579. Return Value:
  580. None.
  581. --*/
  582. {
  583. WCHAR LineString[20];
  584. WCHAR ErrString[32];
  585. WCHAR FileName[MAX_PATH];
  586. WCHAR Buffer[256];
  587. LPWSTR Strings[3];
  588. DWORD Bytes;
  589. LineString[ RTL_NUMBER_OF( LineString ) - 1 ] = UNICODE_NULL;
  590. _snwprintf( LineString, RTL_NUMBER_OF( LineString ) - 1, L"%d", Line );
  591. ErrString[ RTL_NUMBER_OF( ErrString ) - 1 ] = UNICODE_NULL;
  592. _snwprintf( ErrString, RTL_NUMBER_OF( ErrString ) - 1, L"%d", ErrCode);
  593. FileName[ RTL_NUMBER_OF( FileName ) - 1 ] = UNICODE_NULL;
  594. mbstowcs(FileName, File, RTL_NUMBER_OF( FileName ) - 1);
  595. Strings[0] = LineString;
  596. Strings[1] = FileName;
  597. Strings[2] = ErrString;
  598. ClRtlpReportEvent(EVENTLOG_ERROR_TYPE,
  599. (WORD)LogModule,
  600. MessageId,
  601. 3,
  602. 0,
  603. Strings,
  604. NULL);
  605. Bytes = FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE |
  606. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  607. FORMAT_MESSAGE_MAX_WIDTH_MASK, // remove embedded line breaks
  608. NULL,
  609. MessageId,
  610. 0,
  611. Buffer,
  612. sizeof(Buffer) / sizeof(WCHAR),
  613. (va_list *)Strings);
  614. if (Bytes != 0) {
  615. OutputDebugStringW(Buffer);
  616. ClRtlLogPrint(LOG_CRITICAL, "%1!ws!\n",Buffer);
  617. }
  618. }
  619. VOID
  620. ClusterLogFatalError(
  621. IN ULONG LogModule,
  622. IN ULONG Line,
  623. IN LPSTR File,
  624. IN ULONG ErrCode
  625. )
  626. /*++
  627. Routine Description:
  628. Logs a fatal error to the eventlog and breaks into the debugger if present.
  629. Exits the process on fatal error.
  630. Arguments:
  631. LogModule - Supplies the module.
  632. Line - Supplies the line number of the caller.
  633. File - Supplies the filename of the caller.
  634. ErrCode - Supplies the specific error code.
  635. Return Value:
  636. None.
  637. --*/
  638. {
  639. ClusterCommonLogError(UNEXPECTED_FATAL_ERROR,
  640. LogModule,
  641. Line,
  642. File,
  643. ErrCode);
  644. if (IsDebuggerPresent()) {
  645. DebugBreak();
  646. }
  647. ClRtlpFlushLogBuffers();
  648. ExitProcess(ErrCode);
  649. }
  650. VOID
  651. ClusterLogNonFatalError(
  652. IN ULONG LogModule,
  653. IN ULONG Line,
  654. IN LPSTR File,
  655. IN ULONG ErrCode
  656. )
  657. /*++
  658. Routine Description:
  659. Logs a nonfatal error to the eventlog
  660. Arguments:
  661. LogModule - Supplies the module.
  662. Line - Supplies the line number of the caller.
  663. File - Supplies the filename of the caller.
  664. ErrCode - Supplies the specific error code.
  665. Return Value:
  666. None.
  667. --*/
  668. {
  669. ClusterCommonLogError(LOG_FAILURE,
  670. LogModule,
  671. Line,
  672. File,
  673. ErrCode);
  674. }
  675. VOID
  676. ClusterLogAssertionFailure(
  677. IN ULONG LogModule,
  678. IN ULONG Line,
  679. IN LPSTR File,
  680. IN LPSTR Expression
  681. )
  682. /*++
  683. Routine Description:
  684. Logs an assertion failure to the eventlog.
  685. Arguments:
  686. LogModule - Supplies the module.
  687. Line - Supplies the line number of the caller.
  688. File - Supplies the filename of the caller.
  689. Express - Supplies the ASSERTion expression
  690. Return Value:
  691. None.
  692. --*/
  693. {
  694. WCHAR LineString[10];
  695. WCHAR FileName[MAX_PATH];
  696. WCHAR Buffer[256];
  697. LPWSTR Strings[4];
  698. DWORD Bytes;
  699. LineString[ RTL_NUMBER_OF( LineString ) - 1 ] = UNICODE_NULL;
  700. _snwprintf( LineString, RTL_NUMBER_OF( LineString ) - 1, L"%d", Line );
  701. FileName[ RTL_NUMBER_OF( FileName ) - 1 ] = UNICODE_NULL;
  702. mbstowcs(FileName, File, RTL_NUMBER_OF( FileName ) - 1);
  703. Buffer[ RTL_NUMBER_OF( Buffer ) - 1 ] = UNICODE_NULL;
  704. mbstowcs(Buffer, Expression, RTL_NUMBER_OF( Buffer) - 1);
  705. Strings[0] = LineString;
  706. Strings[1] = FileName;
  707. Strings[2] = Buffer;
  708. ClRtlpReportEvent(EVENTLOG_ERROR_TYPE,
  709. (WORD)LogModule,
  710. ASSERTION_FAILURE,
  711. 3,
  712. 0,
  713. Strings,
  714. NULL);
  715. Bytes = FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE |
  716. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  717. FORMAT_MESSAGE_MAX_WIDTH_MASK, // removed embedded line breaks
  718. NULL,
  719. ASSERTION_FAILURE,
  720. 0,
  721. Buffer,
  722. sizeof(Buffer) / sizeof(WCHAR),
  723. (va_list *)Strings);
  724. if (Bytes != 0) {
  725. OutputDebugStringW(Buffer);
  726. ClRtlLogPrint(LOG_CRITICAL, "%1!ws!\n",Buffer);
  727. }
  728. if (IsDebuggerPresent()) {
  729. DebugBreak();
  730. } else {
  731. ClRtlpFlushLogBuffers();
  732. ExitProcess(Line);
  733. }
  734. }