From 7f642e51670bc38a4ef782a363936850bc2b0ba9 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 06:38:23 -0700 Subject: Move dutil into libs/dutil --- src/libs/dutil/WixToolset.DUtil/dutil.cpp | 524 ++++++++++++++++++++++++++++++ 1 file changed, 524 insertions(+) create mode 100644 src/libs/dutil/WixToolset.DUtil/dutil.cpp (limited to 'src/libs/dutil/WixToolset.DUtil/dutil.cpp') diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.cpp b/src/libs/dutil/WixToolset.DUtil/dutil.cpp new file mode 100644 index 00000000..56b85207 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/dutil.cpp @@ -0,0 +1,524 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +// Exit macros +#define DExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_DUTIL, x, s, __VA_ARGS__) +#define DExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_DUTIL, x, s, __VA_ARGS__) +#define DExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_DUTIL, x, s, __VA_ARGS__) +#define DExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_DUTIL, x, s, __VA_ARGS__) +#define DExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_DUTIL, x, s, __VA_ARGS__) +#define DExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_DUTIL, x, s, __VA_ARGS__) +#define DExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_DUTIL, p, x, e, s, __VA_ARGS__) +#define DExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_DUTIL, p, x, s, __VA_ARGS__) +#define DExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_DUTIL, p, x, e, s, __VA_ARGS__) +#define DExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_DUTIL, p, x, s, __VA_ARGS__) +#define DExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_DUTIL, e, x, s, __VA_ARGS__) +#define DExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_DUTIL, g, x, s, __VA_ARGS__) + +// No need for OACR to warn us about using non-unicode APIs in this file. +#pragma prefast(disable:25068) + +// Asserts & Tracing + +const int DUTIL_STRING_BUFFER = 1024; +static HMODULE Dutil_hAssertModule = NULL; +static DUTIL_ASSERTDISPLAYFUNCTION Dutil_pfnDisplayAssert = NULL; +static BOOL Dutil_fNoAsserts = FALSE; +static REPORT_LEVEL Dutil_rlCurrentTrace = REPORT_STANDARD; +static BOOL Dutil_fTraceFilenames = FALSE; +static DUTIL_CALLBACK_TRACEERROR vpfnTraceErrorCallback = NULL; + + +DAPI_(HRESULT) DutilInitialize( + __in_opt DUTIL_CALLBACK_TRACEERROR pfnTraceErrorCallback + ) +{ + HRESULT hr = S_OK; + + vpfnTraceErrorCallback = pfnTraceErrorCallback; + + return hr; +} + + +DAPI_(void) DutilUninitialize() +{ + vpfnTraceErrorCallback = NULL; +} + +/******************************************************************* +Dutil_SetAssertModule + +*******************************************************************/ +extern "C" void DAPI Dutil_SetAssertModule( + __in HMODULE hAssertModule + ) +{ + Dutil_hAssertModule = hAssertModule; +} + + +/******************************************************************* +Dutil_SetAssertDisplayFunction + +*******************************************************************/ +extern "C" void DAPI Dutil_SetAssertDisplayFunction( + __in DUTIL_ASSERTDISPLAYFUNCTION pfn + ) +{ + Dutil_pfnDisplayAssert = pfn; +} + + +/******************************************************************* +Dutil_AssertMsg + +*******************************************************************/ +extern "C" void DAPI Dutil_AssertMsg( + __in_z LPCSTR szMessage + ) +{ + static BOOL fInAssert = FALSE; // TODO: make this thread safe (this is a cheap hack to prevent re-entrant Asserts) + + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + int id = IDRETRY; + HKEY hkDebug = NULL; + HANDLE hAssertFile = INVALID_HANDLE_VALUE; + char szPath[MAX_PATH] = { }; + DWORD cch = 0; + + if (fInAssert) + { + return; + } + fInAssert = TRUE; + + char szMsg[DUTIL_STRING_BUFFER]; + hr = ::StringCchCopyA(szMsg, countof(szMsg), szMessage); + DExitOnFailure(hr, "failed to copy message while building assert message"); + + if (Dutil_pfnDisplayAssert) + { + // call custom function to display the assert string + if (!Dutil_pfnDisplayAssert(szMsg)) + { + ExitFunction(); + } + } + else + { + OutputDebugStringA(szMsg); + } + + if (!Dutil_fNoAsserts) + { + er = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Delivery\\Debug", 0, KEY_QUERY_VALUE, &hkDebug); + if (ERROR_SUCCESS == er) + { + cch = countof(szPath); + er = ::RegQueryValueExA(hkDebug, "DeliveryAssertsLog", NULL, NULL, reinterpret_cast(szPath), &cch); + szPath[countof(szPath) - 1] = '\0'; // ensure string is null terminated since registry won't guarantee that. + if (ERROR_SUCCESS == er) + { + hAssertFile = ::CreateFileA(szPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE != hAssertFile) + { + if (INVALID_SET_FILE_POINTER != ::SetFilePointer(hAssertFile, 0, 0, FILE_END)) + { + if (SUCCEEDED(::StringCchCatA(szMsg, countof(szMsg), "\r\n"))) + { + ::WriteFile(hAssertFile, szMsg, lstrlenA(szMsg), &cch, NULL); + } + } + } + } + } + + // if anything went wrong while fooling around with the registry, just show the usual assert dialog box + if (ERROR_SUCCESS != er) + { + hr = ::StringCchCatA(szMsg, countof(szMsg), "\nAbort=Debug, Retry=Skip, Ignore=Skip all"); + DExitOnFailure(hr, "failed to concat string while building assert message"); + + id = ::MessageBoxA(0, szMsg, "Debug Assert Message", + MB_SERVICE_NOTIFICATION | MB_TOPMOST | + MB_DEFBUTTON2 | MB_ABORTRETRYIGNORE); + } + } + + if (id == IDABORT) + { + if (Dutil_hAssertModule) + { + ::GetModuleFileNameA(Dutil_hAssertModule, szPath, countof(szPath)); + + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "Module is running from: %s\nIf you are not using pdb-stamping, place your PDB near the module and attach to process id: %d (0x%x)", szPath, ::GetCurrentProcessId(), ::GetCurrentProcessId()); + if (SUCCEEDED(hr)) + { + ::MessageBoxA(0, szMsg, "Debug Assert Message", MB_SERVICE_NOTIFICATION | MB_TOPMOST | MB_OK); + } + } + + ::DebugBreak(); + } + else if (id == IDIGNORE) + { + Dutil_fNoAsserts = TRUE; + } + +LExit: + ReleaseFileHandle(hAssertFile); + ReleaseRegKey(hkDebug); + fInAssert = FALSE; +} + + +/******************************************************************* +Dutil_Assert + +*******************************************************************/ +extern "C" void DAPI Dutil_Assert( + __in_z LPCSTR szFile, + __in int iLine + ) +{ + HRESULT hr = S_OK; + char szMessage[DUTIL_STRING_BUFFER] = { }; + hr = ::StringCchPrintfA(szMessage, countof(szMessage), "Assertion failed in %s, %i", szFile, iLine); + if (SUCCEEDED(hr)) + { + Dutil_AssertMsg(szMessage); + } + else + { + Dutil_AssertMsg("Assert failed to build string"); + } +} + + +/******************************************************************* +Dutil_AssertSz + +*******************************************************************/ +extern "C" void DAPI Dutil_AssertSz( + __in_z LPCSTR szFile, + __in int iLine, + __in_z __format_string LPCSTR szMsg + ) +{ + HRESULT hr = S_OK; + char szMessage[DUTIL_STRING_BUFFER] = { }; + + hr = ::StringCchPrintfA(szMessage, countof(szMessage), "Assertion failed in %s, %i\n%s", szFile, iLine, szMsg); + if (SUCCEEDED(hr)) + { + Dutil_AssertMsg(szMessage); + } + else + { + Dutil_AssertMsg("Assert failed to build string"); + } +} + + +/******************************************************************* +Dutil_TraceSetLevel + +*******************************************************************/ +extern "C" void DAPI Dutil_TraceSetLevel( + __in REPORT_LEVEL rl, + __in BOOL fTraceFilenames + ) +{ + Dutil_rlCurrentTrace = rl; + Dutil_fTraceFilenames = fTraceFilenames; +} + + +/******************************************************************* +Dutil_TraceGetLevel + +*******************************************************************/ +extern "C" REPORT_LEVEL DAPI Dutil_TraceGetLevel() +{ + return Dutil_rlCurrentTrace; +} + + +/******************************************************************* +Dutil_Trace + +*******************************************************************/ +extern "C" void DAPIV Dutil_Trace( + __in_z LPCSTR szFile, + __in int iLine, + __in REPORT_LEVEL rl, + __in_z __format_string LPCSTR szFormat, + ... + ) +{ + AssertSz(REPORT_NONE != rl, "REPORT_NONE is not a valid tracing level"); + + HRESULT hr = S_OK; + char szOutput[DUTIL_STRING_BUFFER] = { }; + char szMsg[DUTIL_STRING_BUFFER] = { }; + + if (Dutil_rlCurrentTrace < rl) + { + return; + } + + va_list args; + va_start(args, szFormat); + hr = ::StringCchVPrintfA(szOutput, countof(szOutput), szFormat, args); + va_end(args); + + if (SUCCEEDED(hr)) + { + LPCSTR szPrefix = "Trace/u"; + switch (rl) + { + case REPORT_STANDARD: + szPrefix = "Trace/s"; + break; + case REPORT_VERBOSE: + szPrefix = "Trace/v"; + break; + case REPORT_DEBUG: + szPrefix = "Trace/d"; + break; + } + + if (Dutil_fTraceFilenames) + { + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "%s [%s,%d]: %s\r\n", szPrefix, szFile, iLine, szOutput); + } + else + { + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "%s: %s\r\n", szPrefix, szOutput); + } + + if (SUCCEEDED(hr)) + { + OutputDebugStringA(szMsg); + } + // else fall through to the case below + } + + if (FAILED(hr)) + { + if (Dutil_fTraceFilenames) + { + ::StringCchPrintfA(szMsg, countof(szMsg), "Trace [%s,%d]: message too long, skipping\r\n", szFile, iLine); + } + else + { + ::StringCchPrintfA(szMsg, countof(szMsg), "Trace: message too long, skipping\r\n"); + } + + szMsg[countof(szMsg)-1] = '\0'; + OutputDebugStringA(szMsg); + } +} + + +/******************************************************************* +Dutil_TraceError + +*******************************************************************/ +extern "C" void DAPIV Dutil_TraceError( + __in_z LPCSTR szFile, + __in int iLine, + __in REPORT_LEVEL rl, + __in HRESULT hrError, + __in_z __format_string LPCSTR szFormat, + ... + ) +{ + HRESULT hr = S_OK; + char szOutput[DUTIL_STRING_BUFFER] = { }; + char szMsg[DUTIL_STRING_BUFFER] = { }; + + // if this is NOT an error report and we're not logging at this level, bail + if (REPORT_ERROR != rl && Dutil_rlCurrentTrace < rl) + { + return; + } + + va_list args; + va_start(args, szFormat); + hr = ::StringCchVPrintfA(szOutput, countof(szOutput), szFormat, args); + va_end(args); + + if (SUCCEEDED(hr)) + { + if (Dutil_fTraceFilenames) + { + if (FAILED(hrError)) + { + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x [%s,%d]: %s\r\n", hrError, szFile, iLine, szOutput); + } + else + { + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError [%s,%d]: %s\r\n", szFile, iLine, szOutput); + } + } + else + { + if (FAILED(hrError)) + { + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x: %s\r\n", hrError, szOutput); + } + else + { + hr = ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError: %s\r\n", szOutput); + } + } + + if (SUCCEEDED(hr)) + { + OutputDebugStringA(szMsg); + } + // else fall through to the failure case below + } + + if (FAILED(hr)) + { + if (Dutil_fTraceFilenames) + { + if (FAILED(hrError)) + { + ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x [%s,%d]: message too long, skipping\r\n", hrError, szFile, iLine); + } + else + { + ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError [%s,%d]: message too long, skipping\r\n", szFile, iLine); + } + } + else + { + if (FAILED(hrError)) + { + ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError 0x%x: message too long, skipping\r\n", hrError); + } + else + { + ::StringCchPrintfA(szMsg, countof(szMsg), "TraceError: message too long, skipping\r\n"); + } + } + + szMsg[countof(szMsg)-1] = '\0'; + OutputDebugStringA(szMsg); + } +} + + +DAPIV_(void) Dutil_TraceErrorSource( + __in_z LPCSTR szFile, + __in int iLine, + __in REPORT_LEVEL rl, + __in UINT source, + __in HRESULT hr, + __in_z __format_string LPCSTR szFormat, + ... + ) +{ + // if this is NOT an error report and we're not logging at this level, bail + if (REPORT_ERROR != rl && Dutil_rlCurrentTrace < rl) + { + return; + } + + if (DUTIL_SOURCE_UNKNOWN != source && vpfnTraceErrorCallback) + { + va_list args; + va_start(args, szFormat); + vpfnTraceErrorCallback(szFile, iLine, rl, source, hr, szFormat, args); + va_end(args); + } +} + + +/******************************************************************* +Dutil_RootFailure + +*******************************************************************/ +extern "C" void DAPI Dutil_RootFailure( + __in_z LPCSTR szFile, + __in int iLine, + __in HRESULT hrError + ) +{ +#ifndef DEBUG + UNREFERENCED_PARAMETER(szFile); + UNREFERENCED_PARAMETER(iLine); + UNREFERENCED_PARAMETER(hrError); +#endif // DEBUG + + TraceError(hrError, "Root failure at %s:%d", szFile, iLine); +} + +/******************************************************************* + LoadSystemLibrary - Fully qualifies the path to a module in the + Windows system directory and loads it. + + Returns + E_MODNOTFOUND - The module could not be found. + * - Another error occured. +********************************************************************/ +extern "C" HRESULT DAPI LoadSystemLibrary( + __in_z LPCWSTR wzModuleName, + __out HMODULE *phModule + ) +{ + HRESULT hr = LoadSystemLibraryWithPath(wzModuleName, phModule, NULL); + return hr; +} + +/******************************************************************* + LoadSystemLibraryWithPath - Fully qualifies the path to a module in + the Windows system directory and loads it + and returns the path + + Returns + E_MODNOTFOUND - The module could not be found. + * - Another error occured. +********************************************************************/ +extern "C" HRESULT DAPI LoadSystemLibraryWithPath( + __in_z LPCWSTR wzModuleName, + __out HMODULE *phModule, + __deref_out_z_opt LPWSTR* psczPath + ) +{ + HRESULT hr = S_OK; + DWORD cch = 0; + WCHAR wzPath[MAX_PATH] = { }; + + cch = ::GetSystemDirectoryW(wzPath, MAX_PATH); + DExitOnNullWithLastError(cch, hr, "Failed to get the Windows system directory."); + + if (L'\\' != wzPath[cch - 1]) + { + hr = ::StringCchCatNW(wzPath, MAX_PATH, L"\\", 1); + DExitOnRootFailure(hr, "Failed to terminate the string with a backslash."); + } + + hr = ::StringCchCatW(wzPath, MAX_PATH, wzModuleName); + DExitOnRootFailure(hr, "Failed to create the fully-qualified path to %ls.", wzModuleName); + + *phModule = ::LoadLibraryW(wzPath); + DExitOnNullWithLastError(*phModule, hr, "Failed to load the library %ls.", wzModuleName); + + if (psczPath) + { + hr = StrAllocString(psczPath, wzPath, MAX_PATH); + DExitOnFailure(hr, "Failed to copy the path to library."); + } + +LExit: + return hr; +} -- cgit v1.2.3-55-g6feb