|
|
#include "stdinc.h"
#include "fusioneventlog.h"
#include "search.h"
#include <stdlib.h>
#include "fusionunused.h"
#include "sxsid.h"
#include "smartptr.h"
/*
NTRAID#NTBUG9-591790-2002/03/31-JayKrell
General issues in this file missing error check on .Win32Format (dbgprint related, under #if DBG)
//
// ISSUE:jonwis:2002-3-29: This version is smarter about rolling back if something bad
// happens, and much better about playing nice with tracing and whatnot. It should be
// put into place at some point, but it's too much of a change to just make offhand.
//
static BOOL FusionpRegisterEventLog()
Registration of the our event logging should be moved to a setup text file.
FormatMessage with inserts is not "safe". Our code depends on our resources. Our code picks some maximums that our resources need to stay under.
CEventLogLastError::CEventLogLastError() and CEventLogLastError::CEventLogLastError(DWORD) are copy pastes of each other; they should share code
*/
/*--------------------------------------------------------------------------
--------------------------------------------------------------------------*/
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 = RTL_CONSTANT_STRING(EVENT_SOURCE);
// 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 szEventMessageFileName[] = L"EventMessageFile";
static const WCHAR szEventMessageFileValue[] = MESSAGE_FILE; static const HKEY hkeyEventLogRoot = HKEY_LOCAL_MACHINE; #define EVENT_LOG_SUBKEY_PARENT L"System\\CurrentControlSet\\Services\\EventLog\\System\\"
#define EVENT_LOG_SUBKEY (EVENT_LOG_SUBKEY_PARENT EVENT_SOURCE)
const static PCUNICODE_STRING 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) ) { if (pvReserved != NULL) { ::ElfDeregisterEventSource(g_hEventLog); } g_hEventLog = NULL; } return TRUE; }
const static WCHAR Error_Message_is_unavailable[] = L"Error Message is unavailable\n";
/*--------------------------------------------------------------------------
--------------------------------------------------------------------------*/ CEventLogLastError::CEventLogLastError() { const DWORD dwLastError = FusionpGetLastWin32Error();
// extra string copy..
WCHAR rgchLastError[NUMBER_OF(m_rgchBuffer)]; rgchLastError[0] = 0;
C_ASSERT(sizeof(Error_Message_is_unavailable) <= sizeof(rgchLastError));
// 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 ) { CopyMemory(rgchLastError, Error_Message_is_unavailable, sizeof(Error_Message_is_unavailable)); }
// 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;
C_ASSERT(sizeof(Error_Message_is_unavailable) <= sizeof(rgchLastError));
// 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) { CopyMemory(rgchLastError, Error_Message_is_unavailable, sizeof(Error_Message_is_unavailable)); }
// 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 --------------------------------------------------------------------------*/
// NTRAID#NTBUG9 - 566261 - jonwis - 2002/4/25 - We should be doing better in terms of rollback
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, szEventMessageFileName, 0, // reserved
REG_EXPAND_SZ, reinterpret_cast<const BYTE*>(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<const BYTE*>(&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<HKEY>(INVALID_HANDLE_VALUE);
ASSERT(szParentKey[NUMBER_OF(szSubKey) - NUMBER_OF(szEventSource)] == L'\\'); szParentKey[NUMBER_OF(szSubKey) - NUMBER_OF(szEventSource)] = 0;
::RegDeleteValueW(hkey, szEventMessageFileName); ::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 --------------------------------------------------------------------------*/ 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<const EventIdErrorPair*>( bsearch( &key, &eventIdToErrorMap, numberOf, sizeof(eventIdToErrorMap[0]), reinterpret_cast<PFNBSearchFunction>(CompareEventIdErrorPair))); } else { found = reinterpret_cast<const EventIdErrorPair*>( _lfind( &key, &eventIdToErrorMap, &numberOf, sizeof(eventIdToErrorMap[0]), reinterpret_cast<PFNBSearchFunction>(CompareEventIdErrorPair))); } if (found == NULL) { #if DBG
CANSIStringBuffer msg; msg.Win32Format("Event id %lx not found in eventIdToErrorMap", static_cast<ULONG>(dwEventId)); ASSERT2_NTC(found != NULL, const_cast<PSTR>(static_cast<PCSTR>(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 --------------------------------------------------------------------------*/ BOOL FusionpOpenEventLog() { HANDLE hEventLog; NTSTATUS status; if (g_fEventLogOpenAttempted) { goto Exit; } if (!FusionpRegisterEventLog()) { goto Exit; } status = ::ElfRegisterEventSourceW( const_cast<PUNICODE_STRING>(&strMachine), const_cast<PUNICODE_STRING>(&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<ULONG>(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 ) { PCUNICODE_STRING 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 ) { PCUNICODE_STRING 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 ) { PCUNICODE_STRING rgps[] = { &s1, &s2, &s3, &s4 }; return FusionpLogErrorToEventLog(dwEventId, NUMBER_OF(rgps), rgps); }
void LocalFreeWcharPointer( WCHAR * p ) { LocalFree(p); }
/*--------------------------------------------------------------------------
--------------------------------------------------------------------------*/
HRESULT FusionpLogErrorToDebugger( DWORD dwEventId, ULONG nStrings, const PCUNICODE_STRING * rgps ) { const LONG lastError = FusionpEventIdToError(dwEventId); const HRESULT hr = HRESULT_FROM_WIN32(lastError);
PCUNICODE_STRING 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)) { CopyMemory(rgpsManyStrings, rgps, nStrings * sizeof(rgps[0])); rgps = rgpsManyStrings; }
DWORD dwFormatMessageFlags = 0;
CSmartPtrWithNamedDestructor<WCHAR, LocalFreeWcharPointer> pszBuffer1; CSmartPtrWithNamedDestructor<WCHAR, LocalFreeWcharPointer> pszBuffer2; DWORD dw = 0; static const WCHAR rgchParseContextPrefix[] = PARSE_CONTEXT_PREFIX; const SIZE_T cchParseContextPrefixLength = RTL_NUMBER_OF(rgchParseContextPrefix) - 1; 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; dwFormatMessageFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; dw = FormatMessageW( dwFormatMessageFlags, g_hInstance, dwEventId, 0, // langid
reinterpret_cast<PWSTR>(static_cast<PWSTR*>(&pszBuffer1)), 300, // minimum allocation
const_cast<va_list*>(reinterpret_cast<const va_list*>(&percentZw))); if (dw == 0) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/FormatMessageW failed %ld\n", static_cast<long>(FusionpGetLastWin32Error())); goto Exit; }
// do the substitutions
dwFormatMessageFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING; dwFormatMessageFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; dw = FormatMessageW( dwFormatMessageFlags, pszBuffer1, 0, // message id
0, // langid
reinterpret_cast<PWSTR>(static_cast<PWSTR*>(&pszBuffer2)), 1 + StringLength(pszBuffer1), // minimum allocation
reinterpret_cast<va_list*>(const_cast<PUNICODE_STRING*>(rgps))); if (dw == 0) { ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: FusionpLogError/FormatMessageW failed %ld\n", static_cast<long>(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(pszBuffer2, '\n'); BOOL fAreWeInOSSetupMode = FALSE; FusionpAreWeInOSSetupMode(&fAreWeInOSSetupMode); if ( pszSkipFirstLine != NULL && nStrings >= PARSE_CONTEXT_INSERTS_END && StringLength(pszBuffer2) >= cchParseContextPrefixLength && FusionpEqualStringsI(pszBuffer2, cchParseContextPrefixLength, rgchParseContextPrefix, cchParseContextPrefixLength) ) { // 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), "%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), "SXS.DLL: %S", pszBuffer2); } Exit: ::SetLastError(lastError); return hr; }
/*--------------------------------------------------------------------------
--------------------------------------------------------------------------*/
HRESULT FusionpLogErrorToEventLog( DWORD dwEventId, ULONG nStrings, const PCUNICODE_STRING * 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<WORD>(HRESULT_FACILITY(dwEventId) & 0xff)*/; const DWORD dwDataSize = 0; void const* const pvRawData = NULL; const PSID pSecurityIdentifier = NULL;
if (!::FusionpOpenEventLog()) { goto Exit; } else { NTSTATUS status; status = ::ElfReportEventW( g_hEventLog, wType, wCategory, dwEventId, pSecurityIdentifier, static_cast<USHORT>(nStrings), dwDataSize, const_cast<PUNICODE_STRING*>(rgps), const_cast<void*>(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<ULONG>(status)); goto Exit; } } Exit: ::SetLastError(lastError); return hr; }
/*--------------------------------------------------------------------------
--------------------------------------------------------------------------*/
HRESULT FusionpLogError( DWORD dwEventId, ULONG nStrings, const PCUNICODE_STRING * 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, PCUNICODE_STRING p1, PCUNICODE_STRING p2, PCUNICODE_STRING p3, PCUNICODE_STRING p4, PCUNICODE_STRING p5, PCUNICODE_STRING p6, PCUNICODE_STRING p7, PCUNICODE_STRING p8, PCUNICODE_STRING p9, PCUNICODE_STRING p10, PCUNICODE_STRING p11, PCUNICODE_STRING p12, PCUNICODE_STRING p13, PCUNICODE_STRING p14, PCUNICODE_STRING p15, PCUNICODE_STRING p16, PCUNICODE_STRING p17, PCUNICODE_STRING p18, PCUNICODE_STRING p19, PCUNICODE_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 const PCUNICODE_STRING 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 }; PCUNICODE_STRING 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)); }
|