#include "stdinc.h" #include "FusionEventLog.h" #include "search.h" #include #include "fusionunused.h" #include "sxsid.h" /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ const UNICODE_STRING g_strEmptyUnicodeString = { 0, 0, L""}; extern HINSTANCE g_hInstance; HANDLE g_hEventLog = NULL; BOOL g_fEventLogOpenAttempted = FALSE; // a registry key name, and appears in the EventVwr ui. // should be localized? // a macro is provided for easy static concatenation #define EVENT_SOURCE L"SideBySide" // path we put in the registry to our message file // we might want to change this to ntdll.dll or kernel32.dll // whatever file it is, you can't replace it while EventVwr is running, which stinks #define MESSAGE_FILE L"%SystemRoot%\\System32\\sxs.dll" // the non macro, string pool formed, to use for other than string concatenation const WCHAR szEventSource[] = EVENT_SOURCE; // same thing in another form const static UNICODE_STRING strEventSource = CONSTANT_UNICODE_STRING(szEventSource); // machine is assumed to be the local machine const static UNICODE_STRING strMachine = {0, 0, NULL}; // we only actually log errors, but this is far and away the most common value in the registry // and there doesn't seem to be a downside to using it static const DWORD dwEventTypesSupported = (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE); // a registry value name static const WCHAR szTypesSupportedName[] = L"TypesSupported"; // a registry value name static const WCHAR szEventMessagFileName[] = L"EventMessageFile"; static const WCHAR szEventMessageFileValue[] = MESSAGE_FILE; static const HKEY hkeyEventLogRoot = HKEY_LOCAL_MACHINE; #define EVENT_LOG_SUBKEY L"System\\CurrentControlSet\\Services\\EventLog\\System\\" EVENT_SOURCE static UNICODE_STRING const* const g_rgpsEmptyStrings[] = { &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString }; /*-------------------------------------------------------------------------- call this from DllMain --------------------------------------------------------------------------*/ BOOL FusionpEventLogMain( HINSTANCE, DWORD dwReason, PVOID pvReserved ) { if ((dwReason == DLL_PROCESS_DETACH) && (g_hEventLog != NULL)) { ::ElfDeregisterEventSource(g_hEventLog); g_hEventLog = NULL; } return TRUE; } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ CEventLogLastError::CEventLogLastError() { const DWORD dwLastError = FusionpGetLastWin32Error(); // extra string copy.. WCHAR rgchLastError[NUMBER_OF(m_rgchBuffer)]; rgchLastError[0] = 0; // I expect FormatMessage will truncate, which is acceptable. const DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY; if (::FormatMessageW(dwFlags, NULL, dwLastError, 0, rgchLastError, NUMBER_OF(rgchLastError), NULL) == 0 ) wcscpy(rgchLastError, L"Error Message is unavailable\n"); // Format will truncate, which is acceptable. //Format(L"FusionpGetLastWin32Error()=(%ld,%ls)", nLastError, rgchLastError); Format(L"%ls", rgchLastError); SetLastError(dwLastError); } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ CEventLogLastError::CEventLogLastError( DWORD dwLastError ) { // extra string copy.. WCHAR rgchLastError[NUMBER_OF(m_rgchBuffer)]; rgchLastError[0] = 0; // I expect FormatMessage will truncate, which is acceptable. const DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY; if (::FormatMessageW(dwFlags, NULL, dwLastError, 0, rgchLastError, NUMBER_OF(rgchLastError), NULL) == 0) wcscpy(rgchLastError, L"Error Message is unavailable\n"); // Format will truncate, which is acceptable. //Format(L"FusionpGetLastWin32Error()=(%ld,%ls)", nLastError, rgchLastError); Format(L"%ls", rgchLastError); SetLastError(dwLastError); } /*-------------------------------------------------------------------------- register ourselves in the registry on demand FUTURE Do this in setup? HKLM\System\CurrentControlSet\Services\EventLog\System\SideBySide EventMessageFile = %SystemRoot%\System32\Fusion.dll TypesSupported = 7 --------------------------------------------------------------------------*/ static BOOL FusionpRegisterEventLog() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); HKEY hkey = NULL; BOOL fValidHkey = FALSE; LONG lRet = ERROR_SUCCESS; DWORD dwDisposition = 0; WCHAR szSubKey[] = EVENT_LOG_SUBKEY; // first see if it's there, in which case we have less to do lRet = ::RegOpenKeyExW( hkeyEventLogRoot, szSubKey, 0, // reserved options KEY_READ | FUSIONP_KEY_WOW64_64KEY, &hkey); if (lRet == ERROR_SUCCESS) { fValidHkey = TRUE; goto Exit; } if (lRet != ERROR_FILE_NOT_FOUND && lRet != ERROR_PATH_NOT_FOUND) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpRegisterEventLog/RegOpenKeyExW failed %ld\n", lRet); goto Exit; } lRet = ::RegCreateKeyExW( hkeyEventLogRoot, szSubKey, 0, // reserved NULL, // class REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | FUSIONP_KEY_WOW64_64KEY, NULL, // security &hkey, &dwDisposition); if (lRet != ERROR_SUCCESS) { goto Exit; } fValidHkey = TRUE; lRet = ::RegSetValueExW( hkey, szEventMessagFileName, 0, // reserved REG_EXPAND_SZ, reinterpret_cast(szEventMessageFileValue), sizeof(szEventMessageFileValue)); if (lRet != ERROR_SUCCESS) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpRegisterEventLog/RegSetValueExW failed %ld\n", lRet); goto Exit; } lRet = ::RegSetValueExW( hkey, szTypesSupportedName, 0, // reserved REG_DWORD, reinterpret_cast(&dwEventTypesSupported), sizeof(dwEventTypesSupported)); if (lRet != ERROR_SUCCESS) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpRegisterEventLog/RegSetValueExW failed %ld\n", lRet); goto Exit; } Exit: if (fValidHkey) { if (lRet != ERROR_SUCCESS) { if (dwDisposition == REG_CREATED_NEW_KEY) { // rollback if there definitely wasn't anything there before PWSTR szParentKey = szSubKey; LONG lSubRet = ERROR_SUCCESS; HKEY hkeyParent = reinterpret_cast(INVALID_HANDLE_VALUE); ASSERT(szParentKey[NUMBER_OF(szSubKey) - NUMBER_OF(szEventSource)] == L'\\'); szParentKey[NUMBER_OF(szSubKey) - NUMBER_OF(szEventSource)] = 0; ::RegDeleteValueW(hkey, szEventMessagFileName); ::RegDeleteValueW(hkey, szTypesSupportedName); lSubRet = ::RegOpenKeyExW( hkeyEventLogRoot, szParentKey, 0, // reserved options KEY_WRITE | FUSIONP_KEY_WOW64_64KEY, &hkeyParent); if (lSubRet == ERROR_SUCCESS) { ::RegDeleteKeyW(hkeyParent, szEventSource); ::RegCloseKey(hkeyParent); } } } ::RegCloseKey(hkey); fValidHkey = FALSE; } if (lRet != ERROR_SUCCESS) { ::SetLastError(lRet); } else fSuccess = TRUE; return fSuccess; } /*-------------------------------------------------------------------------- convert the upper two bits of an event id to the small numbered analogous parameter to ReportEvent --------------------------------------------------------------------------*/ static WORD FusionpEventIdToEventType( DWORD dwEventId ) { switch (dwEventId >> 30) { case STATUS_SEVERITY_SUCCESS: return EVENTLOG_SUCCESS; case STATUS_SEVERITY_WARNING: return EVENTLOG_WARNING_TYPE; case STATUS_SEVERITY_INFORMATIONAL: return EVENTLOG_INFORMATION_TYPE; case STATUS_SEVERITY_ERROR: return EVENTLOG_ERROR_TYPE; default: __assume(FALSE); } __assume(FALSE); } /*-------------------------------------------------------------------------- a Fusion event id and its corresponding Win32 lastError the mapping is defined in Messages.x --------------------------------------------------------------------------*/ struct EventIdErrorPair { DWORD dwEventId; LONG nError; }; /*-------------------------------------------------------------------------- the type of function used with bsearch --------------------------------------------------------------------------*/ typedef int (__cdecl* PFNBSearchFunction)(const void*, const void*); /*-------------------------------------------------------------------------- a function appropriate for use with bsearch --------------------------------------------------------------------------*/ int __cdecl CompareEventIdErrorPair( const EventIdErrorPair* x, const EventIdErrorPair* y ) { return (x->dwEventId < y->dwEventId) ? -1 : (x->dwEventId > y->dwEventId) ? +1 : 0; } const static EventIdErrorPair eventIdToErrorMap[] = { #include "Messages.hi" // generated from .x file, like .mc }; /*-------------------------------------------------------------------------- find the Win32 last error corresponding to this Fusion event id --------------------------------------------------------------------------*/ DWORD FusionpEventIdToError( DWORD dwEventId ) { DWORD dwFacility = HRESULT_FACILITY(dwEventId); if (dwFacility < 0x100) { // it's actually a system event id ASSERT2_NTC(FALSE, "system event id in " __FUNCTION__); return dwEventId; } static BOOL fSortVerified = FALSE; static BOOL fSorted = FALSE; if (!fSortVerified) { ULONG i; for (i = 0 ; i != NUMBER_OF(eventIdToErrorMap) - 1; ++i) { if (eventIdToErrorMap[i+1].dwEventId < eventIdToErrorMap[i].dwEventId) { break; } } if (i != NUMBER_OF(eventIdToErrorMap) - 1) { ASSERT2_NTC(FALSE, "eventIdToErrorMap is not sorted, reverting to linear search"); fSorted = FALSE; } else { fSorted = TRUE; } fSortVerified = TRUE; } const EventIdErrorPair* found = NULL; const EventIdErrorPair key = { dwEventId }; unsigned numberOf = NUMBER_OF(eventIdToErrorMap); if (fSorted) { found = reinterpret_cast( bsearch( &key, &eventIdToErrorMap, numberOf, sizeof(eventIdToErrorMap[0]), reinterpret_cast(CompareEventIdErrorPair))); } else { found = reinterpret_cast( _lfind( &key, &eventIdToErrorMap, &numberOf, sizeof(eventIdToErrorMap[0]), reinterpret_cast(CompareEventIdErrorPair))); } if (found == NULL) { #if DBG CANSIStringBuffer msg; msg.Win32Format("Event id %lx not found in eventIdToErrorMap", static_cast(dwEventId)); ASSERT2_NTC(found != NULL, const_cast(static_cast(msg))); #endif return ::FusionpGetLastWin32Error(); } if (found->nError != 0) { return found->nError; } return ::FusionpGetLastWin32Error(); } /*-------------------------------------------------------------------------- open the event log on demand confusingly, this is called "registering" an event source --------------------------------------------------------------------------*/ static BOOL FusionpOpenEventLog() { HANDLE hEventLog; NTSTATUS status; if (g_fEventLogOpenAttempted) { goto Exit; } if (!FusionpRegisterEventLog()) { goto Exit; } status = ::ElfRegisterEventSourceW( const_cast(&strMachine), const_cast(&strEventSource), &hEventLog); if (!NT_SUCCESS(status)) { if (status != RPC_NT_SERVER_UNAVAILABLE) ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpOpenEventLog/ElfRegisterEventSourceW failed %lx\n", static_cast(status)); goto Exit; } if (InterlockedCompareExchangePointer( &g_hEventLog, hEventLog, // exchange value NULL // compare value ) != NULL) // value returned is value that was there before we called { ::ElfDeregisterEventSource(hEventLog); goto Exit; } g_hEventLog = hEventLog; Exit: g_fEventLogOpenAttempted = TRUE; return (g_hEventLog != NULL); } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ HRESULT FusionpLogError( DWORD dwEventId, const UNICODE_STRING& s1, const UNICODE_STRING& s2, const UNICODE_STRING& s3, const UNICODE_STRING& s4 ) { UNICODE_STRING const* rgps[] = { &s1, &s2, &s3, &s4 }; return ::FusionpLogError(dwEventId, NUMBER_OF(rgps), rgps); } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ HRESULT FusionpLogErrorToDebugger( DWORD dwEventId, const UNICODE_STRING& s1, const UNICODE_STRING& s2, const UNICODE_STRING& s3, const UNICODE_STRING& s4 ) { UNICODE_STRING const* rgps[] = { &s1, &s2, &s3, &s4 }; return FusionpLogErrorToDebugger(dwEventId, NUMBER_OF(rgps), rgps); } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ HRESULT FusionpLogErrorToEventLog( DWORD dwEventId, const UNICODE_STRING& s1, const UNICODE_STRING& s2, const UNICODE_STRING& s3, const UNICODE_STRING& s4 ) { UNICODE_STRING const* rgps[] = { &s1, &s2, &s3, &s4 }; return FusionpLogErrorToEventLog(dwEventId, NUMBER_OF(rgps), rgps); } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ HRESULT FusionpLogErrorToDebugger( DWORD dwEventId, ULONG nStrings, UNICODE_STRING const* const* rgps ) { const LONG lastError = FusionpEventIdToError(dwEventId); const HRESULT hr = HRESULT_FROM_WIN32(lastError); UNICODE_STRING const* rgpsManyStrings[] = { &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString, &g_strEmptyUnicodeString }; if (nStrings < NUMBER_OF(rgpsManyStrings)) { memcpy(rgpsManyStrings, rgps, nStrings * sizeof(rgps[0])); rgps = rgpsManyStrings; } DWORD dwFormatMessageFlags = 0; WCHAR rgchBuffer1[300]; WCHAR rgchBuffer2[300]; rgchBuffer1[0] = 0; rgchBuffer2[0] = 0; DWORD dw = 0; static const WCHAR rgchParseContextPrefix[] = PARSE_CONTEXT_PREFIX; PCWSTR pszSkipFirstLine = NULL; // load the string from the message table, // substituting %n with %n!wZ! // the Rtl limit here is 200, but we don't expect very many in our messages const static PCWSTR percentZw[] = { L"%1!wZ!", L"%2!wZ!", L"%3!wZ!", L"%4!wZ!", L"%5!wZ!", L"%6!wZ!", L"%7!wZ!", L"%8!wZ!", L"%9!wZ!", L"%10!wZ!", L"%11!wZ!", L"%12!wZ!", L"%13!wZ!", L"%14!wZ!", L"%15!wZ!" L"%16!wZ!", L"%17!wZ!", L"%18!wZ!", L"%19!wZ!", L"%20!wZ!" }; dwFormatMessageFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_HMODULE; dw = FormatMessageW( dwFormatMessageFlags, g_hInstance, dwEventId, 0, // langid rgchBuffer1, NUMBER_OF(rgchBuffer1), const_cast(reinterpret_cast(&percentZw))); if (dw == 0) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/FormatMessageW failed %ld\n", static_cast(FusionpGetLastWin32Error())); goto Exit; } // do the substitutions dwFormatMessageFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING; dw = FormatMessageW( dwFormatMessageFlags, rgchBuffer1, 0, // message id 0, // langid rgchBuffer2, NUMBER_OF(rgchBuffer2), reinterpret_cast(const_cast(rgps))); if (dw == 0) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/FormatMessageW failed %ld\n", static_cast(FusionpGetLastWin32Error())); goto Exit; } // // acceptable hack // // The first line of parse errors is a verbose context, see Messages.x. // For DbgPrint we want instead file(line): on the same line instead. // We make that transformation here. // pszSkipFirstLine = wcschr(rgchBuffer2, '\n'); BOOL fAreWeInOSSetupMode = FALSE; FusionpAreWeInOSSetupMode(&fAreWeInOSSetupMode); if ( pszSkipFirstLine != NULL && nStrings >= PARSE_CONTEXT_INSERTS_END && memcmp(rgchBuffer2, rgchParseContextPrefix, sizeof(rgchParseContextPrefix)-sizeof(WCHAR)) == 0 ) { // we might fiddle with the form of the newline, so skip whatever is there while (wcschr(L"\r\n", *pszSkipFirstLine) != NULL) pszSkipFirstLine += 1; ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR | ( fAreWeInOSSetupMode ? FUSION_DBG_LEVEL_SETUPLOG : 0), //FUSION_DBG_LEVEL_ERROR, "%wZ(%wZ): %S", rgps[PARSE_CONTEXT_FILE - 1], rgps[PARSE_CONTEXT_LINE - 1], pszSkipFirstLine); } else { // just print it verbatim FusionpDbgPrintEx( FUSION_DBG_LEVEL_ERROR | ( fAreWeInOSSetupMode ? FUSION_DBG_LEVEL_SETUPLOG : 0), //FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %S", rgchBuffer2); } Exit: ::SetLastError(lastError); return hr; } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ HRESULT FusionpLogErrorToEventLog( DWORD dwEventId, ULONG nStrings, UNICODE_STRING const* const* rgps ) { const LONG lastError = FusionpEventIdToError(dwEventId); const HRESULT hr = HRESULT_FROM_WIN32(lastError); const WORD wType = FusionpEventIdToEventType(dwEventId); // The use of the lower bits of the hresult facility as the event log // facility is my own invention, but it seems a good one. // ReportEvent has too many parameters, those three integers instead of one. const WORD wCategory = 0/*static_cast(HRESULT_FACILITY(dwEventId) & 0xff)*/; const DWORD dwDataSize = 0; void const* const pvRawData = NULL; const PSID pSecurityIdentifier = NULL; if (!::FusionpOpenEventLog()) { //::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpOpenEventLog failed\n"); // error msg has print before exit goto Exit; } else { NTSTATUS status; status = ::ElfReportEventW( g_hEventLog, wType, wCategory, dwEventId, pSecurityIdentifier, static_cast(nStrings), dwDataSize, const_cast(rgps), const_cast(pvRawData), 0, NULL, NULL); // // the excluded error status is because it is in the early setup time. // if (!NT_SUCCESS(status)) { if (status != RPC_NT_SERVER_UNAVAILABLE) ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/ElfReportEventW failed %lx\n", static_cast(status)); goto Exit; } } Exit: ::SetLastError(lastError); return hr; } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ HRESULT FusionpLogError( DWORD dwEventId, ULONG nStrings, UNICODE_STRING const* const* rgps ) { const HRESULT hr = FusionpLogErrorToEventLog(dwEventId, nStrings, rgps); const HRESULT hr2 = FusionpLogErrorToDebugger(dwEventId, nStrings, rgps); RETAIL_UNUSED(hr); RETAIL_UNUSED(hr2); ASSERT_NTC(hr == hr2); return hr; } HRESULT FusionpLogParseError( PCWSTR FilePath, SIZE_T FilePathCch, ULONG LineNumber, DWORD dwLastParseError, const UNICODE_STRING *p1, const UNICODE_STRING *p2, const UNICODE_STRING *p3, const UNICODE_STRING *p4, const UNICODE_STRING *p5, const UNICODE_STRING *p6, const UNICODE_STRING *p7, const UNICODE_STRING *p8, const UNICODE_STRING *p9, const UNICODE_STRING *p10, const UNICODE_STRING *p11, const UNICODE_STRING *p12, const UNICODE_STRING *p13, const UNICODE_STRING *p14, const UNICODE_STRING *p15, const UNICODE_STRING *p16, const UNICODE_STRING *p17, const UNICODE_STRING *p18, const UNICODE_STRING *p19, const UNICODE_STRING *p20 ) { const DWORD lastError = ::FusionpEventIdToError(dwLastParseError); const HRESULT hr = HRESULT_FROM_WIN32(lastError); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_INFO, "SXS.DLL: %s() entered\n", __FUNCTION__); // // FormatMessage (actually sprintf) AVs on NULL UNICODE_STRING* // and/or when we don't pass enough of them; // we can't tell it how many strings we are passing, // and it isn't easy to tell how many it needs, // so we load it up with a bunch of extra non NULL ones. // Besides that, we have holes to fill. // static const UNICODE_STRING s_strEmptyUnicodeString = { 0, 0, L""}; static UNICODE_STRING const* const s_rgpsEmptyStrings[] = { &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString, &s_strEmptyUnicodeString }; UNICODE_STRING const* rgpsAll[NUMBER_OF(s_rgpsEmptyStrings)]; memcpy(&rgpsAll, s_rgpsEmptyStrings, sizeof(rgpsAll)); #define HANDLE_STRING(_n) do { if (p ## _n != NULL) rgpsAll[_n - 1] = p ## _n; } while (0) HANDLE_STRING(1); HANDLE_STRING(2); HANDLE_STRING(3); HANDLE_STRING(4); HANDLE_STRING(5); HANDLE_STRING(6); HANDLE_STRING(7); HANDLE_STRING(8); HANDLE_STRING(9); HANDLE_STRING(10); HANDLE_STRING(11); HANDLE_STRING(12); HANDLE_STRING(13); HANDLE_STRING(14); HANDLE_STRING(15); HANDLE_STRING(16); HANDLE_STRING(17); HANDLE_STRING(18); HANDLE_STRING(19); HANDLE_STRING(20); #undef HANDLE_STRING // // form up some "context" UNICODE_STRINGs and put them in the array of pointers // the first two are the ones that we always use, even for DbgPrint // CEventLogString file(FilePath, FilePathCch); CEventLogInteger lineNumber(LineNumber); rgpsAll[PARSE_CONTEXT_FILE - 1] = &file; rgpsAll[PARSE_CONTEXT_LINE - 1] = &lineNumber; ::FusionpLogErrorToEventLog( dwLastParseError, NUMBER_OF(rgpsAll), rgpsAll); // we should tell this function that it was a parse error and to do // the context munging, but it detects it itself imperfectly ::FusionpLogErrorToDebugger(dwLastParseError, NUMBER_OF(rgpsAll), rgpsAll); ::FusionpDbgPrintEx( FUSION_DBG_LEVEL_INFO, "SXS.DLL: %s():%#lx exited\n", __FUNCTION__, hr); ::SetLastError(lastError); return hr; } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ VOID FusionpLogRequiredAttributeMissingParseError( PCWSTR SourceFilePath, SIZE_T SourceFileCch, ULONG LineNumber, PCWSTR ElementName, SIZE_T ElementNameCch, PCWSTR AttributeName, SIZE_T AttributeNameCch ) { ::FusionpLogParseError( SourceFilePath, SourceFileCch, LineNumber, MSG_SXS_XML_REQUIRED_ATTRIBUTE_MISSING, CEventLogString(ElementName, ElementNameCch), CEventLogString(AttributeName, AttributeNameCch)); } VOID FusionpLogInvalidAttributeValueParseError( PCWSTR SourceFilePath, SIZE_T SourceFileCch, ULONG LineNumber, PCWSTR ElementName, SIZE_T ElementNameCch, PCWSTR AttributeName, SIZE_T AttributeNameCch ) { ::FusionpLogParseError( SourceFilePath, SourceFileCch, LineNumber, MSG_SXS_XML_INVALID_ATTRIBUTE_VALUE, CEventLogString(ElementName, ElementNameCch), CEventLogString(AttributeName, AttributeNameCch)); } VOID FusionpLogInvalidAttributeValueParseError( PCWSTR SourceFilePath, SIZE_T SourceFileCch, ULONG LineNumber, PCWSTR ElementName, SIZE_T ElementNameCch, const SXS_ASSEMBLY_IDENTITY_ATTRIBUTE_REFERENCE &rAttribute ) { ::FusionpLogInvalidAttributeValueParseError( SourceFilePath, SourceFileCch, LineNumber, ElementName, ElementNameCch, rAttribute.Name, rAttribute.NameCch); } VOID FusionpLogAttributeNotAllowedParseError( PCWSTR SourceFilePath, SIZE_T SourceFileCch, ULONG LineNumber, PCWSTR ElementName, SIZE_T ElementNameCch, PCWSTR AttributeName, SIZE_T AttributeNameCch ) { ::FusionpLogParseError( SourceFilePath, SourceFileCch, LineNumber, MSG_SXS_XML_ATTRIBUTE_NOT_ALLOWED, CEventLogString(ElementName, ElementNameCch), CEventLogString(AttributeName, AttributeNameCch)); } VOID FusionpLogWin32ErrorToEventLog() { DWORD dwLastError = ::FusionpGetLastWin32Error(); if (dwLastError == 0 ) return; FusionpLogError(MSG_SXS_WIN32_ERROR_MSG, CEventLogLastError(dwLastError)); }