From 30827588eb0c189b7e2d04693d116080d333200e Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 15:43:19 -0700 Subject: Move wcautil into libs/wcautil --- src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp | 269 +++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp (limited to 'src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp') diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp new file mode 100644 index 00000000..cc7d1438 --- /dev/null +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcalog.cpp @@ -0,0 +1,269 @@ +// 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" + +/******************************************************************** + IsVerboseLoggingPolicy() - internal helper function to detect if + policy is set for verbose logging. Does + not require database access. +********************************************************************/ +static BOOL IsVerboseLoggingPolicy() +{ + BOOL fVerbose = FALSE; + HKEY hkey = NULL; + WCHAR rgwc[16] = { 0 }; + DWORD cb = sizeof(rgwc); + if (ERROR_SUCCESS == ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Policies\\Microsoft\\Windows\\Installer", 0, KEY_QUERY_VALUE, &hkey)) + { + if (ERROR_SUCCESS == ::RegQueryValueExW(hkey, L"Logging", 0, NULL, reinterpret_cast(rgwc), &cb)) + { + for (LPCWSTR pwc = rgwc; (cb / sizeof(WCHAR)) > static_cast(pwc - rgwc) && *pwc; pwc++) + { + if (L'v' == *pwc || L'V' == *pwc) + { + fVerbose = TRUE; + break; + } + } + } + + ::RegCloseKey(hkey); + } + return fVerbose; +} + +/******************************************************************** + IsVerboseLogging() - internal helper function to detect if doing + verbose logging. Checks: + 1. LOGVERBOSE property. + 2. MsiLogging property contains 'v' + 3. Policy from registry. + + Requires database access. +********************************************************************/ +BOOL WIXAPI IsVerboseLogging() +{ + static int iVerbose = -1; + LPWSTR pwzMsiLogging = NULL; + + if (0 > iVerbose) + { + iVerbose = WcaIsPropertySet("LOGVERBOSE"); + if (0 == iVerbose) + { + // if the property wasn't set, check the MsiLogging property (MSI 4.0+) + HRESULT hr = WcaGetProperty(L"MsiLogging", &pwzMsiLogging); + ExitOnFailure(hr, "failed to get MsiLogging property"); + + if (pwzMsiLogging) + { + for (int i = 0; pwzMsiLogging[i]; i++) + { + if (L'v' == pwzMsiLogging[i] || L'V' == pwzMsiLogging[i]) + { + iVerbose = 1; + break; + } + } + } + + // last chance: Check the registry to see if the logging policy was turned on + if (0 == iVerbose && IsVerboseLoggingPolicy()) + { + iVerbose = 1; + } + } + } + +LExit: + ReleaseStr(pwzMsiLogging); + Assert(iVerbose >= 0); + return (BOOL)iVerbose; +} + +/******************************************************************** + SetVerboseLoggingAtom() - Sets one of two global Atoms to specify + if the install should do verbose logging. + Communicates the verbose setting to + deferred CAs. + Set a negative case atom so that we can + distinguish between an unset atom and the + non-verbose case. This helps prevent the + expensive regkey lookup for non-verbose. +********************************************************************/ +HRESULT WIXAPI SetVerboseLoggingAtom(BOOL bValue) +{ + HRESULT hr = S_OK; + ATOM atomVerbose = 0; + + atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging"); + if (0 == atomVerbose && bValue) + { + atomVerbose = ::GlobalAddAtomW(L"WcaVerboseLogging"); + ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaVerboseLogging global atom."); + } + else if (0 != atomVerbose && !bValue) + { + ::SetLastError(ERROR_SUCCESS); + ::GlobalDeleteAtom(atomVerbose); + ExitOnLastError(hr, "Failed to delete WcaVerboseLogging global atom."); + } + + atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging"); + if (0 == atomVerbose && !bValue) + { + atomVerbose = ::GlobalAddAtomW(L"WcaNotVerboseLogging"); + ExitOnNullWithLastError(atomVerbose, hr, "Failed to create WcaNotVerboseLogging global atom."); + } + else if (0 != atomVerbose && bValue) + { + ::SetLastError(ERROR_SUCCESS); + ::GlobalDeleteAtom(atomVerbose); + ExitOnLastError(hr, "Failed to delete WcaNotVerboseLogging global atom."); + } + +LExit: + return hr; +} + +/******************************************************************** + IsVerboseLoggingLite() - internal helper function to detect if atom was + previously set to specify verbose logging. + Falls back on policy for an installer that is + unable to set the atom (no immediate CAs). + + Does not require database access. +********************************************************************/ +static BOOL IsVerboseLoggingLite() +{ + ATOM atomVerbose = ::GlobalFindAtomW(L"WcaVerboseLogging"); + if (0 != atomVerbose) + { + return TRUE; + } + + atomVerbose = ::GlobalFindAtomW(L"WcaNotVerboseLogging"); + if (0 != atomVerbose) + { + return FALSE; + } + + return IsVerboseLoggingPolicy(); +} + +/******************************************************************** + WcaLog() - outputs trace and log info + +*******************************************************************/ +extern "C" void __cdecl WcaLog( + __in LOGLEVEL llv, + __in_z __format_string PCSTR fmt, + ... + ) +{ + static char szFmt[LOG_BUFFER]; + static char szBuf[LOG_BUFFER]; + static bool fInLogPrint = false; + + // prevent re-entrant logprints. (recursion issues between assert/logging code) + if (fInLogPrint) + return; + fInLogPrint = true; + + if (LOGMSG_STANDARD == llv || + (LOGMSG_VERBOSE == llv && IsVerboseLoggingLite()) +#ifdef DEBUG + || LOGMSG_TRACEONLY == llv +#endif + ) + { + va_list args; + va_start(args, fmt); + + LPCSTR szLogName = WcaGetLogName(); + if (szLogName[0] != 0) + StringCchPrintfA(szFmt, countof(szFmt), "%s: %s", szLogName, fmt); + else + StringCchCopyA(szFmt, countof(szFmt), fmt); + + StringCchVPrintfA(szBuf, countof(szBuf), szFmt, args); + va_end(args); + +#ifdef DEBUG + // always write to the log in debug +#else + if (llv == LOGMSG_STANDARD || (llv == LOGMSG_VERBOSE && IsVerboseLoggingLite())) +#endif + { + PMSIHANDLE hrec = MsiCreateRecord(1); + + ::MsiRecordSetStringA(hrec, 0, szBuf); + // TODO: Recursion on failure. May not be safe to assert from here. + WcaProcessMessage(INSTALLMESSAGE_INFO, hrec); + } + +#if DEBUG + StringCchCatA(szBuf, countof(szBuf), "\n"); + OutputDebugStringA(szBuf); +#endif + } + + fInLogPrint = false; + return; +} + + +/******************************************************************** + WcaDisplayAssert() - called before Assert() dialog shows + + NOTE: writes the assert string to the MSI log +********************************************************************/ +extern "C" BOOL WIXAPI WcaDisplayAssert( + __in LPCSTR sz + ) +{ + WcaLog(LOGMSG_STANDARD, "Debug Assert Message: %s", sz); + return TRUE; +} + + +/******************************************************************** + WcaLogError() - called before ExitOnXXX() macro exits the function + + NOTE: writes the hresult and error string to the MSI log +********************************************************************/ +extern "C" void WcaLogError( + __in HRESULT hr, + __in LPCSTR szMessage, + ... + ) +{ + va_list dots; + + va_start(dots, szMessage); + WcaLogErrorArgs(hr, szMessage, dots); + va_end(dots); +} + + +/******************************************************************** + WcaLogErrorArgs() - called before ExitOnXXX() macro exits the function + + NOTE: writes the hresult and error string to the MSI log +********************************************************************/ +extern "C" void WcaLogErrorArgs( + __in HRESULT hr, + __in LPCSTR szMessage, + __in va_list args + ) +{ + char szBuffer[LOG_BUFFER]; + + StringCchVPrintfA(szBuffer, countof(szBuffer), szMessage, args); + + // log the message if using Wca common layer + if (WcaIsInitialized()) + { + WcaLog(LOGMSG_STANDARD, "Error 0x%x: %s", hr, szBuffer); + } +} -- cgit v1.2.3-55-g6feb