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

#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));
}