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.

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