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.

864 lines
28 KiB

  1. #include "stdinc.h"
  2. #include "FusionEventLog.h"
  3. #include "search.h"
  4. #include <stdlib.h>
  5. #include "fusionunused.h"
  6. #include "sxsid.h"
  7. /*--------------------------------------------------------------------------
  8. --------------------------------------------------------------------------*/
  9. const UNICODE_STRING g_strEmptyUnicodeString = { 0, 0, L""};
  10. extern HINSTANCE g_hInstance;
  11. HANDLE g_hEventLog = NULL;
  12. BOOL g_fEventLogOpenAttempted = FALSE;
  13. // a registry key name, and appears in the EventVwr ui.
  14. // should be localized?
  15. // a macro is provided for easy static concatenation
  16. #define EVENT_SOURCE L"SideBySide"
  17. // path we put in the registry to our message file
  18. // we might want to change this to ntdll.dll or kernel32.dll
  19. // whatever file it is, you can't replace it while EventVwr is running, which stinks
  20. #define MESSAGE_FILE L"%SystemRoot%\\System32\\sxs.dll"
  21. // the non macro, string pool formed, to use for other than string concatenation
  22. const WCHAR szEventSource[] = EVENT_SOURCE;
  23. // same thing in another form
  24. const static UNICODE_STRING strEventSource = CONSTANT_UNICODE_STRING(szEventSource);
  25. // machine is assumed to be the local machine
  26. const static UNICODE_STRING strMachine = {0, 0, NULL};
  27. // we only actually log errors, but this is far and away the most common value in the registry
  28. // and there doesn't seem to be a downside to using it
  29. static const DWORD dwEventTypesSupported = (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE);
  30. // a registry value name
  31. static const WCHAR szTypesSupportedName[] = L"TypesSupported";
  32. // a registry value name
  33. static const WCHAR szEventMessagFileName[] = L"EventMessageFile";
  34. static const WCHAR szEventMessageFileValue[] = MESSAGE_FILE;
  35. static const HKEY hkeyEventLogRoot = HKEY_LOCAL_MACHINE;
  36. #define EVENT_LOG_SUBKEY L"System\\CurrentControlSet\\Services\\EventLog\\System\\" EVENT_SOURCE
  37. static UNICODE_STRING const* const g_rgpsEmptyStrings[] =
  38. {
  39. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  40. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  41. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  42. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  43. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString
  44. };
  45. /*--------------------------------------------------------------------------
  46. call this from DllMain
  47. --------------------------------------------------------------------------*/
  48. BOOL
  49. FusionpEventLogMain(
  50. HINSTANCE,
  51. DWORD dwReason,
  52. PVOID pvReserved
  53. )
  54. {
  55. if ((dwReason == DLL_PROCESS_DETACH) &&
  56. (g_hEventLog != NULL))
  57. {
  58. ::ElfDeregisterEventSource(g_hEventLog);
  59. g_hEventLog = NULL;
  60. }
  61. return TRUE;
  62. }
  63. /*--------------------------------------------------------------------------
  64. --------------------------------------------------------------------------*/
  65. CEventLogLastError::CEventLogLastError()
  66. {
  67. const DWORD dwLastError = FusionpGetLastWin32Error();
  68. // extra string copy..
  69. WCHAR rgchLastError[NUMBER_OF(m_rgchBuffer)];
  70. rgchLastError[0] = 0;
  71. // I expect FormatMessage will truncate, which is acceptable.
  72. const DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
  73. if (::FormatMessageW(dwFlags, NULL, dwLastError, 0, rgchLastError, NUMBER_OF(rgchLastError), NULL) == 0 )
  74. wcscpy(rgchLastError, L"Error Message is unavailable\n");
  75. // Format will truncate, which is acceptable.
  76. //Format(L"FusionpGetLastWin32Error()=(%ld,%ls)", nLastError, rgchLastError);
  77. Format(L"%ls", rgchLastError);
  78. SetLastError(dwLastError);
  79. }
  80. /*--------------------------------------------------------------------------
  81. --------------------------------------------------------------------------*/
  82. CEventLogLastError::CEventLogLastError(
  83. DWORD dwLastError
  84. )
  85. {
  86. // extra string copy..
  87. WCHAR rgchLastError[NUMBER_OF(m_rgchBuffer)];
  88. rgchLastError[0] = 0;
  89. // I expect FormatMessage will truncate, which is acceptable.
  90. const DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
  91. if (::FormatMessageW(dwFlags, NULL, dwLastError, 0, rgchLastError, NUMBER_OF(rgchLastError), NULL) == 0)
  92. wcscpy(rgchLastError, L"Error Message is unavailable\n");
  93. // Format will truncate, which is acceptable.
  94. //Format(L"FusionpGetLastWin32Error()=(%ld,%ls)", nLastError, rgchLastError);
  95. Format(L"%ls", rgchLastError);
  96. SetLastError(dwLastError);
  97. }
  98. /*--------------------------------------------------------------------------
  99. register ourselves in the registry on demand
  100. FUTURE Do this in setup?
  101. HKLM\System\CurrentControlSet\Services\EventLog\System\SideBySide
  102. EventMessageFile = %SystemRoot%\System32\Fusion.dll
  103. TypesSupported = 7
  104. --------------------------------------------------------------------------*/
  105. static BOOL
  106. FusionpRegisterEventLog()
  107. {
  108. BOOL fSuccess = FALSE;
  109. FN_TRACE_WIN32(fSuccess);
  110. HKEY hkey = NULL;
  111. BOOL fValidHkey = FALSE;
  112. LONG lRet = ERROR_SUCCESS;
  113. DWORD dwDisposition = 0;
  114. WCHAR szSubKey[] = EVENT_LOG_SUBKEY;
  115. // first see if it's there, in which case we have less to do
  116. lRet = ::RegOpenKeyExW(
  117. hkeyEventLogRoot,
  118. szSubKey,
  119. 0, // reserved options
  120. KEY_READ | FUSIONP_KEY_WOW64_64KEY,
  121. &hkey);
  122. if (lRet == ERROR_SUCCESS)
  123. {
  124. fValidHkey = TRUE;
  125. goto Exit;
  126. }
  127. if (lRet != ERROR_FILE_NOT_FOUND && lRet != ERROR_PATH_NOT_FOUND)
  128. {
  129. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpRegisterEventLog/RegOpenKeyExW failed %ld\n", lRet);
  130. goto Exit;
  131. }
  132. lRet = ::RegCreateKeyExW(
  133. hkeyEventLogRoot,
  134. szSubKey,
  135. 0, // reserved
  136. NULL, // class
  137. REG_OPTION_NON_VOLATILE,
  138. KEY_ALL_ACCESS | FUSIONP_KEY_WOW64_64KEY,
  139. NULL, // security
  140. &hkey,
  141. &dwDisposition);
  142. if (lRet != ERROR_SUCCESS)
  143. {
  144. goto Exit;
  145. }
  146. fValidHkey = TRUE;
  147. lRet = ::RegSetValueExW(
  148. hkey,
  149. szEventMessagFileName,
  150. 0, // reserved
  151. REG_EXPAND_SZ,
  152. reinterpret_cast<const BYTE*>(szEventMessageFileValue),
  153. sizeof(szEventMessageFileValue));
  154. if (lRet != ERROR_SUCCESS)
  155. {
  156. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpRegisterEventLog/RegSetValueExW failed %ld\n", lRet);
  157. goto Exit;
  158. }
  159. lRet = ::RegSetValueExW(
  160. hkey,
  161. szTypesSupportedName,
  162. 0, // reserved
  163. REG_DWORD,
  164. reinterpret_cast<const BYTE*>(&dwEventTypesSupported),
  165. sizeof(dwEventTypesSupported));
  166. if (lRet != ERROR_SUCCESS)
  167. {
  168. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpRegisterEventLog/RegSetValueExW failed %ld\n", lRet);
  169. goto Exit;
  170. }
  171. Exit:
  172. if (fValidHkey)
  173. {
  174. if (lRet != ERROR_SUCCESS)
  175. {
  176. if (dwDisposition == REG_CREATED_NEW_KEY)
  177. {
  178. // rollback if there definitely wasn't anything there before
  179. PWSTR szParentKey = szSubKey;
  180. LONG lSubRet = ERROR_SUCCESS;
  181. HKEY hkeyParent = reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
  182. ASSERT(szParentKey[NUMBER_OF(szSubKey) - NUMBER_OF(szEventSource)] == L'\\');
  183. szParentKey[NUMBER_OF(szSubKey) - NUMBER_OF(szEventSource)] = 0;
  184. ::RegDeleteValueW(hkey, szEventMessagFileName);
  185. ::RegDeleteValueW(hkey, szTypesSupportedName);
  186. lSubRet = ::RegOpenKeyExW(
  187. hkeyEventLogRoot,
  188. szParentKey,
  189. 0, // reserved options
  190. KEY_WRITE | FUSIONP_KEY_WOW64_64KEY,
  191. &hkeyParent);
  192. if (lSubRet == ERROR_SUCCESS)
  193. {
  194. ::RegDeleteKeyW(hkeyParent, szEventSource);
  195. ::RegCloseKey(hkeyParent);
  196. }
  197. }
  198. }
  199. ::RegCloseKey(hkey);
  200. fValidHkey = FALSE;
  201. }
  202. if (lRet != ERROR_SUCCESS)
  203. {
  204. ::SetLastError(lRet);
  205. }
  206. else
  207. fSuccess = TRUE;
  208. return fSuccess;
  209. }
  210. /*--------------------------------------------------------------------------
  211. convert the upper two bits of an event id to the small numbered analogous
  212. parameter to ReportEvent
  213. --------------------------------------------------------------------------*/
  214. static WORD
  215. FusionpEventIdToEventType(
  216. DWORD dwEventId
  217. )
  218. {
  219. switch (dwEventId >> 30)
  220. {
  221. case STATUS_SEVERITY_SUCCESS: return EVENTLOG_SUCCESS;
  222. case STATUS_SEVERITY_WARNING: return EVENTLOG_WARNING_TYPE;
  223. case STATUS_SEVERITY_INFORMATIONAL: return EVENTLOG_INFORMATION_TYPE;
  224. case STATUS_SEVERITY_ERROR: return EVENTLOG_ERROR_TYPE;
  225. default: __assume(FALSE);
  226. }
  227. __assume(FALSE);
  228. }
  229. /*--------------------------------------------------------------------------
  230. a Fusion event id and its corresponding Win32 lastError
  231. the mapping is defined in Messages.x
  232. --------------------------------------------------------------------------*/
  233. struct EventIdErrorPair
  234. {
  235. DWORD dwEventId;
  236. LONG nError;
  237. };
  238. /*--------------------------------------------------------------------------
  239. the type of function used with bsearch
  240. --------------------------------------------------------------------------*/
  241. typedef int (__cdecl* PFNBSearchFunction)(const void*, const void*);
  242. /*--------------------------------------------------------------------------
  243. a function appropriate for use with bsearch
  244. --------------------------------------------------------------------------*/
  245. int __cdecl
  246. CompareEventIdErrorPair(
  247. const EventIdErrorPair* x,
  248. const EventIdErrorPair* y
  249. )
  250. {
  251. return
  252. (x->dwEventId < y->dwEventId) ? -1
  253. : (x->dwEventId > y->dwEventId) ? +1
  254. : 0;
  255. }
  256. const static EventIdErrorPair eventIdToErrorMap[] =
  257. {
  258. #include "Messages.hi" // generated from .x file, like .mc
  259. };
  260. /*--------------------------------------------------------------------------
  261. find the Win32 last error corresponding to this Fusion event id
  262. --------------------------------------------------------------------------*/
  263. DWORD
  264. FusionpEventIdToError(
  265. DWORD dwEventId
  266. )
  267. {
  268. DWORD dwFacility = HRESULT_FACILITY(dwEventId);
  269. if (dwFacility < 0x100)
  270. { // it's actually a system event id
  271. ASSERT2_NTC(FALSE, "system event id in " __FUNCTION__);
  272. return dwEventId;
  273. }
  274. static BOOL fSortVerified = FALSE;
  275. static BOOL fSorted = FALSE;
  276. if (!fSortVerified)
  277. {
  278. ULONG i;
  279. for (i = 0 ; i != NUMBER_OF(eventIdToErrorMap) - 1; ++i)
  280. {
  281. if (eventIdToErrorMap[i+1].dwEventId < eventIdToErrorMap[i].dwEventId)
  282. {
  283. break;
  284. }
  285. }
  286. if (i != NUMBER_OF(eventIdToErrorMap) - 1)
  287. {
  288. ASSERT2_NTC(FALSE, "eventIdToErrorMap is not sorted, reverting to linear search");
  289. fSorted = FALSE;
  290. }
  291. else
  292. {
  293. fSorted = TRUE;
  294. }
  295. fSortVerified = TRUE;
  296. }
  297. const EventIdErrorPair* found = NULL;
  298. const EventIdErrorPair key = { dwEventId };
  299. unsigned numberOf = NUMBER_OF(eventIdToErrorMap);
  300. if (fSorted)
  301. {
  302. found = reinterpret_cast<const EventIdErrorPair*>(
  303. bsearch(
  304. &key,
  305. &eventIdToErrorMap,
  306. numberOf,
  307. sizeof(eventIdToErrorMap[0]),
  308. reinterpret_cast<PFNBSearchFunction>(CompareEventIdErrorPair)));
  309. }
  310. else
  311. {
  312. found = reinterpret_cast<const EventIdErrorPair*>(
  313. _lfind(
  314. &key,
  315. &eventIdToErrorMap,
  316. &numberOf,
  317. sizeof(eventIdToErrorMap[0]),
  318. reinterpret_cast<PFNBSearchFunction>(CompareEventIdErrorPair)));
  319. }
  320. if (found == NULL)
  321. {
  322. #if DBG
  323. CANSIStringBuffer msg;
  324. msg.Win32Format("Event id %lx not found in eventIdToErrorMap", static_cast<ULONG>(dwEventId));
  325. ASSERT2_NTC(found != NULL, const_cast<PSTR>(static_cast<PCSTR>(msg)));
  326. #endif
  327. return ::FusionpGetLastWin32Error();
  328. }
  329. if (found->nError != 0)
  330. {
  331. return found->nError;
  332. }
  333. return ::FusionpGetLastWin32Error();
  334. }
  335. /*--------------------------------------------------------------------------
  336. open the event log on demand
  337. confusingly, this is called "registering" an event source
  338. --------------------------------------------------------------------------*/
  339. static
  340. BOOL
  341. FusionpOpenEventLog()
  342. {
  343. HANDLE hEventLog;
  344. NTSTATUS status;
  345. if (g_fEventLogOpenAttempted)
  346. {
  347. goto Exit;
  348. }
  349. if (!FusionpRegisterEventLog())
  350. {
  351. goto Exit;
  352. }
  353. status = ::ElfRegisterEventSourceW(
  354. const_cast<UNICODE_STRING*>(&strMachine),
  355. const_cast<UNICODE_STRING*>(&strEventSource),
  356. &hEventLog);
  357. if (!NT_SUCCESS(status))
  358. {
  359. if (status != RPC_NT_SERVER_UNAVAILABLE)
  360. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpOpenEventLog/ElfRegisterEventSourceW failed %lx\n", static_cast<ULONG>(status));
  361. goto Exit;
  362. }
  363. if (InterlockedCompareExchangePointer(
  364. &g_hEventLog,
  365. hEventLog, // exchange value
  366. NULL // compare value
  367. ) != NULL) // value returned is value that was there before we called
  368. {
  369. ::ElfDeregisterEventSource(hEventLog);
  370. goto Exit;
  371. }
  372. g_hEventLog = hEventLog;
  373. Exit:
  374. g_fEventLogOpenAttempted = TRUE;
  375. return (g_hEventLog != NULL);
  376. }
  377. /*--------------------------------------------------------------------------
  378. --------------------------------------------------------------------------*/
  379. HRESULT
  380. FusionpLogError(
  381. DWORD dwEventId,
  382. const UNICODE_STRING& s1,
  383. const UNICODE_STRING& s2,
  384. const UNICODE_STRING& s3,
  385. const UNICODE_STRING& s4
  386. )
  387. {
  388. UNICODE_STRING const* rgps[] = { &s1, &s2, &s3, &s4 };
  389. return ::FusionpLogError(dwEventId, NUMBER_OF(rgps), rgps);
  390. }
  391. /*--------------------------------------------------------------------------
  392. --------------------------------------------------------------------------*/
  393. HRESULT
  394. FusionpLogErrorToDebugger(
  395. DWORD dwEventId,
  396. const UNICODE_STRING& s1,
  397. const UNICODE_STRING& s2,
  398. const UNICODE_STRING& s3,
  399. const UNICODE_STRING& s4
  400. )
  401. {
  402. UNICODE_STRING const* rgps[] = { &s1, &s2, &s3, &s4 };
  403. return FusionpLogErrorToDebugger(dwEventId, NUMBER_OF(rgps), rgps);
  404. }
  405. /*--------------------------------------------------------------------------
  406. --------------------------------------------------------------------------*/
  407. HRESULT
  408. FusionpLogErrorToEventLog(
  409. DWORD dwEventId,
  410. const UNICODE_STRING& s1,
  411. const UNICODE_STRING& s2,
  412. const UNICODE_STRING& s3,
  413. const UNICODE_STRING& s4
  414. )
  415. {
  416. UNICODE_STRING const* rgps[] = { &s1, &s2, &s3, &s4 };
  417. return FusionpLogErrorToEventLog(dwEventId, NUMBER_OF(rgps), rgps);
  418. }
  419. /*--------------------------------------------------------------------------
  420. --------------------------------------------------------------------------*/
  421. HRESULT
  422. FusionpLogErrorToDebugger(
  423. DWORD dwEventId,
  424. ULONG nStrings,
  425. UNICODE_STRING const* const* rgps
  426. )
  427. {
  428. const LONG lastError = FusionpEventIdToError(dwEventId);
  429. const HRESULT hr = HRESULT_FROM_WIN32(lastError);
  430. UNICODE_STRING const* rgpsManyStrings[] =
  431. {
  432. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  433. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  434. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  435. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString,
  436. &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString
  437. };
  438. if (nStrings < NUMBER_OF(rgpsManyStrings))
  439. {
  440. memcpy(rgpsManyStrings, rgps, nStrings * sizeof(rgps[0]));
  441. rgps = rgpsManyStrings;
  442. }
  443. DWORD dwFormatMessageFlags = 0;
  444. WCHAR rgchBuffer1[300];
  445. WCHAR rgchBuffer2[300];
  446. rgchBuffer1[0] = 0;
  447. rgchBuffer2[0] = 0;
  448. DWORD dw = 0;
  449. static const WCHAR rgchParseContextPrefix[] = PARSE_CONTEXT_PREFIX;
  450. PCWSTR pszSkipFirstLine = NULL;
  451. // load the string from the message table,
  452. // substituting %n with %n!wZ!
  453. // the Rtl limit here is 200, but we don't expect very many in our messages
  454. const static PCWSTR percentZw[] = { L"%1!wZ!", L"%2!wZ!", L"%3!wZ!", L"%4!wZ!", L"%5!wZ!",
  455. L"%6!wZ!", L"%7!wZ!", L"%8!wZ!", L"%9!wZ!", L"%10!wZ!",
  456. L"%11!wZ!", L"%12!wZ!", L"%13!wZ!", L"%14!wZ!", L"%15!wZ!"
  457. L"%16!wZ!", L"%17!wZ!", L"%18!wZ!", L"%19!wZ!", L"%20!wZ!"
  458. };
  459. dwFormatMessageFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_HMODULE;
  460. dw = FormatMessageW(
  461. dwFormatMessageFlags,
  462. g_hInstance,
  463. dwEventId,
  464. 0, // langid
  465. rgchBuffer1,
  466. NUMBER_OF(rgchBuffer1),
  467. const_cast<va_list*>(reinterpret_cast<const va_list*>(&percentZw)));
  468. if (dw == 0)
  469. {
  470. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/FormatMessageW failed %ld\n", static_cast<long>(FusionpGetLastWin32Error()));
  471. goto Exit;
  472. }
  473. // do the substitutions
  474. dwFormatMessageFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING;
  475. dw = FormatMessageW(
  476. dwFormatMessageFlags,
  477. rgchBuffer1,
  478. 0, // message id
  479. 0, // langid
  480. rgchBuffer2,
  481. NUMBER_OF(rgchBuffer2),
  482. reinterpret_cast<va_list*>(const_cast<UNICODE_STRING**>(rgps)));
  483. if (dw == 0)
  484. {
  485. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/FormatMessageW failed %ld\n", static_cast<long>(FusionpGetLastWin32Error()));
  486. goto Exit;
  487. }
  488. //
  489. // acceptable hack
  490. //
  491. // The first line of parse errors is a verbose context, see Messages.x.
  492. // For DbgPrint we want instead file(line): on the same line instead.
  493. // We make that transformation here.
  494. //
  495. pszSkipFirstLine = wcschr(rgchBuffer2, '\n');
  496. BOOL fAreWeInOSSetupMode = FALSE;
  497. FusionpAreWeInOSSetupMode(&fAreWeInOSSetupMode);
  498. if (
  499. pszSkipFirstLine != NULL
  500. && nStrings >= PARSE_CONTEXT_INSERTS_END
  501. && memcmp(rgchBuffer2, rgchParseContextPrefix, sizeof(rgchParseContextPrefix)-sizeof(WCHAR)) == 0
  502. )
  503. {
  504. // we might fiddle with the form of the newline, so skip whatever is there
  505. while (wcschr(L"\r\n", *pszSkipFirstLine) != NULL)
  506. pszSkipFirstLine += 1;
  507. ::FusionpDbgPrintEx(
  508. FUSION_DBG_LEVEL_ERROR | ( fAreWeInOSSetupMode ? FUSION_DBG_LEVEL_SETUPLOG : 0),
  509. //FUSION_DBG_LEVEL_ERROR,
  510. "%wZ(%wZ): %S",
  511. rgps[PARSE_CONTEXT_FILE - 1],
  512. rgps[PARSE_CONTEXT_LINE - 1],
  513. pszSkipFirstLine);
  514. }
  515. else
  516. {
  517. // just print it verbatim
  518. FusionpDbgPrintEx(
  519. FUSION_DBG_LEVEL_ERROR | ( fAreWeInOSSetupMode ? FUSION_DBG_LEVEL_SETUPLOG : 0),
  520. //FUSION_DBG_LEVEL_ERROR,
  521. "SXS.DLL: %S",
  522. rgchBuffer2);
  523. }
  524. Exit:
  525. ::SetLastError(lastError);
  526. return hr;
  527. }
  528. /*--------------------------------------------------------------------------
  529. --------------------------------------------------------------------------*/
  530. HRESULT
  531. FusionpLogErrorToEventLog(
  532. DWORD dwEventId,
  533. ULONG nStrings,
  534. UNICODE_STRING const* const* rgps
  535. )
  536. {
  537. const LONG lastError = FusionpEventIdToError(dwEventId);
  538. const HRESULT hr = HRESULT_FROM_WIN32(lastError);
  539. const WORD wType = FusionpEventIdToEventType(dwEventId);
  540. // The use of the lower bits of the hresult facility as the event log
  541. // facility is my own invention, but it seems a good one.
  542. // ReportEvent has too many parameters, those three integers instead of one.
  543. const WORD wCategory = 0/*static_cast<WORD>(HRESULT_FACILITY(dwEventId) & 0xff)*/;
  544. const DWORD dwDataSize = 0;
  545. void const* const pvRawData = NULL;
  546. const PSID pSecurityIdentifier = NULL;
  547. if (!::FusionpOpenEventLog())
  548. {
  549. //::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpOpenEventLog failed\n"); // error msg has print before exit
  550. goto Exit;
  551. }
  552. else
  553. {
  554. NTSTATUS status;
  555. status = ::ElfReportEventW(
  556. g_hEventLog,
  557. wType,
  558. wCategory,
  559. dwEventId,
  560. pSecurityIdentifier,
  561. static_cast<USHORT>(nStrings),
  562. dwDataSize,
  563. const_cast<UNICODE_STRING**>(rgps),
  564. const_cast<void*>(pvRawData),
  565. 0,
  566. NULL,
  567. NULL);
  568. //
  569. // the excluded error status is because it is in the early setup time.
  570. //
  571. if (!NT_SUCCESS(status))
  572. {
  573. if (status != RPC_NT_SERVER_UNAVAILABLE)
  574. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/ElfReportEventW failed %lx\n", static_cast<ULONG>(status));
  575. goto Exit;
  576. }
  577. }
  578. Exit:
  579. ::SetLastError(lastError);
  580. return hr;
  581. }
  582. /*--------------------------------------------------------------------------
  583. --------------------------------------------------------------------------*/
  584. HRESULT
  585. FusionpLogError(
  586. DWORD dwEventId,
  587. ULONG nStrings,
  588. UNICODE_STRING const* const* rgps
  589. )
  590. {
  591. const HRESULT hr = FusionpLogErrorToEventLog(dwEventId, nStrings, rgps);
  592. const HRESULT hr2 = FusionpLogErrorToDebugger(dwEventId, nStrings, rgps);
  593. RETAIL_UNUSED(hr);
  594. RETAIL_UNUSED(hr2);
  595. ASSERT_NTC(hr == hr2);
  596. return hr;
  597. }
  598. HRESULT
  599. FusionpLogParseError(
  600. PCWSTR FilePath,
  601. SIZE_T FilePathCch,
  602. ULONG LineNumber,
  603. DWORD dwLastParseError,
  604. const UNICODE_STRING *p1,
  605. const UNICODE_STRING *p2,
  606. const UNICODE_STRING *p3,
  607. const UNICODE_STRING *p4,
  608. const UNICODE_STRING *p5,
  609. const UNICODE_STRING *p6,
  610. const UNICODE_STRING *p7,
  611. const UNICODE_STRING *p8,
  612. const UNICODE_STRING *p9,
  613. const UNICODE_STRING *p10,
  614. const UNICODE_STRING *p11,
  615. const UNICODE_STRING *p12,
  616. const UNICODE_STRING *p13,
  617. const UNICODE_STRING *p14,
  618. const UNICODE_STRING *p15,
  619. const UNICODE_STRING *p16,
  620. const UNICODE_STRING *p17,
  621. const UNICODE_STRING *p18,
  622. const UNICODE_STRING *p19,
  623. const UNICODE_STRING *p20
  624. )
  625. {
  626. const DWORD lastError = ::FusionpEventIdToError(dwLastParseError);
  627. const HRESULT hr = HRESULT_FROM_WIN32(lastError);
  628. ::FusionpDbgPrintEx(
  629. FUSION_DBG_LEVEL_INFO,
  630. "SXS.DLL: %s() entered\n", __FUNCTION__);
  631. //
  632. // FormatMessage (actually sprintf) AVs on NULL UNICODE_STRING*
  633. // and/or when we don't pass enough of them;
  634. // we can't tell it how many strings we are passing,
  635. // and it isn't easy to tell how many it needs,
  636. // so we load it up with a bunch of extra non NULL ones.
  637. // Besides that, we have holes to fill.
  638. //
  639. static const UNICODE_STRING s_strEmptyUnicodeString = { 0, 0, L""};
  640. static UNICODE_STRING const* const s_rgpsEmptyStrings[] =
  641. {
  642. &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString,
  643. &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString,
  644. &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString,
  645. &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString,
  646. &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString
  647. };
  648. UNICODE_STRING const* rgpsAll[NUMBER_OF(s_rgpsEmptyStrings)];
  649. memcpy(&rgpsAll, s_rgpsEmptyStrings, sizeof(rgpsAll));
  650. #define HANDLE_STRING(_n) do { if (p ## _n != NULL) rgpsAll[_n - 1] = p ## _n; } while (0)
  651. HANDLE_STRING(1);
  652. HANDLE_STRING(2);
  653. HANDLE_STRING(3);
  654. HANDLE_STRING(4);
  655. HANDLE_STRING(5);
  656. HANDLE_STRING(6);
  657. HANDLE_STRING(7);
  658. HANDLE_STRING(8);
  659. HANDLE_STRING(9);
  660. HANDLE_STRING(10);
  661. HANDLE_STRING(11);
  662. HANDLE_STRING(12);
  663. HANDLE_STRING(13);
  664. HANDLE_STRING(14);
  665. HANDLE_STRING(15);
  666. HANDLE_STRING(16);
  667. HANDLE_STRING(17);
  668. HANDLE_STRING(18);
  669. HANDLE_STRING(19);
  670. HANDLE_STRING(20);
  671. #undef HANDLE_STRING
  672. //
  673. // form up some "context" UNICODE_STRINGs and put them in the array of pointers
  674. // the first two are the ones that we always use, even for DbgPrint
  675. //
  676. CEventLogString file(FilePath, FilePathCch);
  677. CEventLogInteger lineNumber(LineNumber);
  678. rgpsAll[PARSE_CONTEXT_FILE - 1] = &file;
  679. rgpsAll[PARSE_CONTEXT_LINE - 1] = &lineNumber;
  680. ::FusionpLogErrorToEventLog(
  681. dwLastParseError,
  682. NUMBER_OF(rgpsAll),
  683. rgpsAll);
  684. // we should tell this function that it was a parse error and to do
  685. // the context munging, but it detects it itself imperfectly
  686. ::FusionpLogErrorToDebugger(dwLastParseError, NUMBER_OF(rgpsAll), rgpsAll);
  687. ::FusionpDbgPrintEx(
  688. FUSION_DBG_LEVEL_INFO,
  689. "SXS.DLL: %s():%#lx exited\n", __FUNCTION__, hr);
  690. ::SetLastError(lastError);
  691. return hr;
  692. }
  693. /*--------------------------------------------------------------------------
  694. --------------------------------------------------------------------------*/
  695. VOID
  696. FusionpLogRequiredAttributeMissingParseError(
  697. PCWSTR SourceFilePath,
  698. SIZE_T SourceFileCch,
  699. ULONG LineNumber,
  700. PCWSTR ElementName,
  701. SIZE_T ElementNameCch,
  702. PCWSTR AttributeName,
  703. SIZE_T AttributeNameCch
  704. )
  705. {
  706. ::FusionpLogParseError(
  707. SourceFilePath,
  708. SourceFileCch,
  709. LineNumber,
  710. MSG_SXS_XML_REQUIRED_ATTRIBUTE_MISSING,
  711. CEventLogString(ElementName, ElementNameCch),
  712. CEventLogString(AttributeName, AttributeNameCch));
  713. }
  714. VOID
  715. FusionpLogInvalidAttributeValueParseError(
  716. PCWSTR SourceFilePath,
  717. SIZE_T SourceFileCch,
  718. ULONG LineNumber,
  719. PCWSTR ElementName,
  720. SIZE_T ElementNameCch,
  721. PCWSTR AttributeName,
  722. SIZE_T AttributeNameCch
  723. )
  724. {
  725. ::FusionpLogParseError(
  726. SourceFilePath,
  727. SourceFileCch,
  728. LineNumber,
  729. MSG_SXS_XML_INVALID_ATTRIBUTE_VALUE,
  730. CEventLogString(ElementName, ElementNameCch),
  731. CEventLogString(AttributeName, AttributeNameCch));
  732. }
  733. VOID
  734. FusionpLogInvalidAttributeValueParseError(
  735. PCWSTR SourceFilePath,
  736. SIZE_T SourceFileCch,
  737. ULONG LineNumber,
  738. PCWSTR ElementName,
  739. SIZE_T ElementNameCch,
  740. const SXS_ASSEMBLY_IDENTITY_ATTRIBUTE_REFERENCE &rAttribute
  741. )
  742. {
  743. ::FusionpLogInvalidAttributeValueParseError(
  744. SourceFilePath,
  745. SourceFileCch,
  746. LineNumber,
  747. ElementName,
  748. ElementNameCch,
  749. rAttribute.Name,
  750. rAttribute.NameCch);
  751. }
  752. VOID
  753. FusionpLogAttributeNotAllowedParseError(
  754. PCWSTR SourceFilePath,
  755. SIZE_T SourceFileCch,
  756. ULONG LineNumber,
  757. PCWSTR ElementName,
  758. SIZE_T ElementNameCch,
  759. PCWSTR AttributeName,
  760. SIZE_T AttributeNameCch
  761. )
  762. {
  763. ::FusionpLogParseError(
  764. SourceFilePath,
  765. SourceFileCch,
  766. LineNumber,
  767. MSG_SXS_XML_ATTRIBUTE_NOT_ALLOWED,
  768. CEventLogString(ElementName, ElementNameCch),
  769. CEventLogString(AttributeName, AttributeNameCch));
  770. }
  771. VOID
  772. FusionpLogWin32ErrorToEventLog()
  773. {
  774. DWORD dwLastError = ::FusionpGetLastWin32Error();
  775. if (dwLastError == 0 )
  776. return;
  777. FusionpLogError(MSG_SXS_WIN32_ERROR_MSG, CEventLogLastError(dwLastError));
  778. }