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