windows-nt/Source/XPSP1/NT/base/win32/fusion/eventlog/eventlog.cpp

865 lines
28 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "stdinc.h"
#include "FusionEventLog.h"
#include "search.h"
#include <stdlib.h>
#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<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, 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<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
--------------------------------------------------------------------------*/
static
BOOL
FusionpOpenEventLog()
{
HANDLE hEventLog;
NTSTATUS status;
if (g_fEventLogOpenAttempted)
{
goto Exit;
}
if (!FusionpRegisterEventLog())
{
goto Exit;
}
status = ::ElfRegisterEventSourceW(
const_cast<UNICODE_STRING*>(&strMachine),
const_cast<UNICODE_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
)
{
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<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;
dw = FormatMessageW(
dwFormatMessageFlags,
rgchBuffer1,
0, // message id
0, // langid
rgchBuffer2,
NUMBER_OF(rgchBuffer2),
reinterpret_cast<va_list*>(const_cast<UNICODE_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(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<WORD>(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<USHORT>(nStrings),
dwDataSize,
const_cast<UNICODE_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,
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));
}