From ff659159e041bf6c083e6b7fcb9b726065a9dd73 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 3 May 2021 09:55:22 -0700 Subject: Move Util.wixext into ext --- src/ext/Util/ca/scaperfexec.cpp | 423 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 src/ext/Util/ca/scaperfexec.cpp (limited to 'src/ext/Util/ca/scaperfexec.cpp') diff --git a/src/ext/Util/ca/scaperfexec.cpp b/src/ext/Util/ca/scaperfexec.cpp new file mode 100644 index 00000000..c5425754 --- /dev/null +++ b/src/ext/Util/ca/scaperfexec.cpp @@ -0,0 +1,423 @@ +// 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" + +typedef DWORD (STDAPICALLTYPE *PFNPERFCOUNTERTEXTSTRINGS)(LPWSTR lpCommandLine, BOOL bQuietModeArg); + +static HRESULT ExecutePerfCounterData( + __in MSIHANDLE hInstall, + __in BOOL fInstall + ); +static HRESULT CreateDataFile( + __in LPCWSTR wzTempFolder, + __in LPCWSTR wzData, + __in BOOL fIniData, + __out HANDLE *phFile, + __out_opt LPWSTR *ppwzFile + ); + + +/******************************************************************** + RegisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering + performance counters + + Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t... +*******************************************************************/ +extern "C" UINT __stdcall RegisterPerfCounterData( + __in MSIHANDLE hInstall + ) +{ + // AssertSz(FALSE, "debug RegisterPerfCounterData()"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "RegisterPerfCounterData"); + ExitOnFailure(hr, "Failed to initialize RegisterPerfCounterData."); + + hr = ExecutePerfCounterData(hInstall, TRUE); + MessageExitOnFailure(hr, msierrInstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table."); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + UnregisterPerfCounterData - CUSTOM ACTION ENTRY POINT for registering + performance counters + + Input: deferred CustomActionData: wzName\twzIniData\twzConstantData\twzName\twzIniData\twzConstantData\t... +*******************************************************************/ +extern "C" UINT __stdcall UnregisterPerfCounterData( + __in MSIHANDLE hInstall + ) +{ + // AssertSz(FALSE, "debug UnregisterPerfCounterData()"); + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, "UnregisterPerfCounterData"); + ExitOnFailure(hr, "Failed to initialize UnregisterPerfCounterData."); + + hr = ExecutePerfCounterData(hInstall, FALSE); + MessageExitOnFailure(hr, msierrUninstallPerfCounterData, "Failed to execute Wix4PerformanceCategory table."); + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +/******************************************************************** + RegisterPerfmon - CUSTOM ACTION ENTRY POINT for registering + counters + + Input: deferred CustomActionData - + wzFile or wzName +*******************************************************************/ +extern "C" UINT __stdcall RegisterPerfmon( + __in MSIHANDLE hInstall + ) +{ +// Assert(FALSE); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + LPWSTR pwzData = NULL; + + HMODULE hMod = NULL; + PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString; + DWORD dwRet; + LPWSTR pwzShortPath = NULL; + DWORD cchShortPath = MAX_PATH; + DWORD cchShortPathLength = 0; + + LPWSTR pwzCommand = NULL; + + hr = WcaInitialize(hInstall, "RegisterPerfmon"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // do the perfmon registration + if (NULL == hMod) + { + hr = LoadSystemLibrary(L"loadperf.dll", &hMod); + } + ExitOnFailure(hr, "failed to load DLL for PerfMon"); + + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "LoadPerfCounterTextStringsW"); + ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon"); + + hr = StrAlloc(&pwzShortPath, cchShortPath); + ExitOnFailure(hr, "failed to allocate string"); + + WcaLog(LOGMSG_VERBOSE, "Converting DLL path to short format: %ls", pwzData); + cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath); + if (cchShortPathLength > cchShortPath) + { + cchShortPath = cchShortPathLength + 1; + hr = StrAlloc(&pwzShortPath, cchShortPath); + ExitOnFailure(hr, "failed to allocate string"); + + cchShortPathLength = ::GetShortPathNameW(pwzData, pwzShortPath, cchShortPath); + } + + if (0 == cchShortPathLength) + { + ExitOnLastError(hr, "failed to get short path format of path: %ls", pwzData); + } + + hr = StrAllocFormatted(&pwzCommand, L"lodctr \"%s\"", pwzShortPath); + ExitOnFailure(hr, "failed to format lodctr string"); + + WcaLog(LOGMSG_VERBOSE, "RegisterPerfmon running command: '%ls'", pwzCommand); + dwRet = (*pfnPerfCounterTextString)(pwzCommand, TRUE); + if (dwRet != ERROR_SUCCESS && dwRet != ERROR_ALREADY_EXISTS) + { + hr = HRESULT_FROM_WIN32(dwRet); + MessageExitOnFailure(hr, msierrPERFMONFailedRegisterDLL, "failed to register with PerfMon, DLL: %ls", pwzData); + } + + hr = S_OK; +LExit: + ReleaseStr(pwzData); + + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +extern "C" UINT __stdcall UnregisterPerfmon( + __in MSIHANDLE hInstall + ) +{ +// Assert(FALSE); + UINT er = ERROR_SUCCESS; + HRESULT hr = S_OK; + LPWSTR pwzData = NULL; + + HMODULE hMod = NULL; + PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString; + DWORD dwRet; + WCHAR wz[255]; + + hr = WcaInitialize(hInstall, "UnregisterPerfmon"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetProperty(L"CustomActionData", &pwzData); + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // do the perfmon unregistration + hr = E_FAIL; + if (hMod == NULL) + { + hr = LoadSystemLibrary(L"loadperf.dll", &hMod); + } + ExitOnFailure(hr, "failed to load DLL for PerfMon"); + + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hMod, "UnloadPerfCounterTextStringsW"); + ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "failed to get DLL function for PerfMon"); + + hr = ::StringCchPrintfW(wz, countof(wz), L"unlodctr \"%s\"", pwzData); + ExitOnFailure(hr, "Failed to format unlodctr string with: %ls", pwzData); + WcaLog(LOGMSG_VERBOSE, "UnregisterPerfmon running command: '%ls'", wz); + dwRet = (*pfnPerfCounterTextString)(wz, TRUE); + // if the counters aren't registered, then OK to continue + if (dwRet != ERROR_SUCCESS && dwRet != ERROR_FILE_NOT_FOUND && dwRet != ERROR_BADKEY) + { + hr = HRESULT_FROM_WIN32(dwRet); + MessageExitOnFailure(hr, msierrPERFMONFailedUnregisterDLL, "failed to unregsister with PerfMon, DLL: %ls", pwzData); + } + + hr = S_OK; +LExit: + ReleaseStr(pwzData); + + if (FAILED(hr)) + er = ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + + +static HRESULT ExecutePerfCounterData( + __in MSIHANDLE /*hInstall*/, + __in BOOL fInstall + ) +{ + HRESULT hr = S_OK; + DWORD er = ERROR_SUCCESS; + + HMODULE hModule = NULL; + PFNPERFCOUNTERTEXTSTRINGS pfnPerfCounterTextString = NULL; + LPCWSTR wzPrefix = NULL; + + LPWSTR pwzCustomActionData = NULL; + LPWSTR pwz = NULL; + + LPWSTR pwzName = NULL; + LPWSTR pwzIniData = NULL; + LPWSTR pwzConstantData = NULL; + LPWSTR pwzTempFolder = NULL; + LPWSTR pwzIniFile = NULL; + LPWSTR pwzExecute = NULL; + + HANDLE hIniData = INVALID_HANDLE_VALUE; + HANDLE hConstantData = INVALID_HANDLE_VALUE; + + // Load the system performance counter helper DLL then get the appropriate + // entrypoint out of it. Fortunately, they have the same signature so we + // can use one function pointer to point to both. + hr = LoadSystemLibrary(L"loadperf.dll", &hModule); + ExitOnFailure(hr, "failed to load DLL for PerfMon"); + + if (fInstall) + { + wzPrefix = L"lodctr"; + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "LoadPerfCounterTextStringsW"); + } + else + { + wzPrefix = L"unlodctr"; + pfnPerfCounterTextString = (PFNPERFCOUNTERTEXTSTRINGS)::GetProcAddress(hModule, "UnloadPerfCounterTextStringsW"); + } + ExitOnNullWithLastError(pfnPerfCounterTextString, hr, "Failed to get DLL function for PerfMon"); + + // Now get the CustomActionData and execute it. + hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData); + ExitOnFailure(hr, "Failed to get CustomActionData."); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); + + pwz = pwzCustomActionData; + + while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzName))) + { + hr = WcaReadStringFromCaData(&pwz, &pwzIniData); + ExitOnFailure(hr, "Failed to read IniData from custom action data."); + + hr = WcaReadStringFromCaData(&pwz, &pwzConstantData); + ExitOnFailure(hr, "Failed to read ConstantData from custom action data."); + + if (fInstall) + { + hr = PathCreateTempDirectory(NULL, L"WIXPF%03x", 999, &pwzTempFolder); + ExitOnFailure(hr, "Failed to create temp directory."); + + hr = CreateDataFile(pwzTempFolder, pwzIniData, TRUE, &hIniData, &pwzIniFile); + ExitOnFailure(hr, "Failed to create .ini file for performance counter category: %ls", pwzName); + + hr = CreateDataFile(pwzTempFolder, pwzConstantData, FALSE, &hConstantData, NULL); + ExitOnFailure(hr, "Failed to create .h file for performance counter category: %ls", pwzName); + + hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzIniFile); + ExitOnFailure(hr, "Failed to allocate string to execute."); + + // Execute the install. + er = (*pfnPerfCounterTextString)(pwzExecute, TRUE); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to execute install of performance counter category: %ls", pwzName); + + if (INVALID_HANDLE_VALUE != hIniData) + { + ::CloseHandle(hIniData); + hIniData = INVALID_HANDLE_VALUE; + } + + if (INVALID_HANDLE_VALUE != hConstantData) + { + ::CloseHandle(hConstantData); + hConstantData = INVALID_HANDLE_VALUE; + } + + DirEnsureDelete(pwzTempFolder, TRUE, TRUE); + } + else + { + hr = StrAllocFormatted(&pwzExecute, L"%s \"%s\"", wzPrefix, pwzName); + ExitOnFailure(hr, "Failed to allocate string to execute."); + + // Execute the uninstall and if the counter isn't registered then ignore + // the error since it won't hurt anything. + er = (*pfnPerfCounterTextString)(pwzExecute, TRUE); + if (ERROR_FILE_NOT_FOUND == er || ERROR_BADKEY == er) + { + er = ERROR_SUCCESS; + } + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "Failed to execute uninstall of performance counter category: %ls", pwzName); + } + } + + if (E_NOMOREITEMS == hr) // If there are no more items, all is well + { + hr = S_OK; + } + ExitOnFailure(hr, "Failed to execute all perf counter data."); + + hr = S_OK; + +LExit: + if (INVALID_HANDLE_VALUE != hIniData) + { + ::CloseHandle(hIniData); + } + + if (INVALID_HANDLE_VALUE != hConstantData) + { + ::CloseHandle(hConstantData); + } + + ReleaseStr(pwzExecute); + ReleaseStr(pwzIniFile); + ReleaseStr(pwzTempFolder); + ReleaseStr(pwzConstantData); + ReleaseStr(pwzIniData); + ReleaseStr(pwzName); + ReleaseStr(pwzCustomActionData); + + if (hModule) + { + ::FreeLibrary(hModule); + } + + return hr; +} + + +static HRESULT CreateDataFile( + __in LPCWSTR wzTempFolder, + __in LPCWSTR wzData, + __in BOOL fIniData, + __out HANDLE *phFile, + __out_opt LPWSTR *ppwzFile + ) +{ + HRESULT hr = S_OK; + HANDLE hFile = INVALID_HANDLE_VALUE; + LPWSTR pwzFile = NULL; + LPSTR pszData = NULL; + DWORD cbData = 0; + DWORD cbWritten = 0; + + // Convert the data to UTF-8 because lodctr/unloctr + // doesn't like unicode. + hr = StrAnsiAllocString(&pszData, wzData, 0, CP_UTF8); + ExitOnFailure(hr, "Failed to covert data to ANSI."); + + cbData = lstrlenA(pszData); + + // Concatenate the paths together, open the file data file + // and dump the data in there. + hr = StrAllocString(&pwzFile, wzTempFolder, 0); + ExitOnFailure(hr, "Failed to copy temp directory name."); + + hr = StrAllocConcat(&pwzFile, L"wixperf", 0); + ExitOnFailure(hr, "Failed to add name of file."); + + hr = StrAllocConcat(&pwzFile, fIniData ? L".ini" : L".h", 0); + ExitOnFailure(hr, "Failed to add extension of file."); + + hFile = ::CreateFileW(pwzFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) + { + ExitWithLastError(hr, "Failed to open new temp file: %ls", pwzFile); + } + + if (!::WriteFile(hFile, pszData, cbData, &cbWritten, NULL)) + { + ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFile); + } + + if (INVALID_HANDLE_VALUE != hFile) + { + ::CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; + } + + // Return the requested values. + *phFile = hFile; + hFile = INVALID_HANDLE_VALUE; + + if (ppwzFile) + { + *ppwzFile = pwzFile; + pwzFile = NULL; + } + +LExit: + if (INVALID_HANDLE_VALUE != hFile) + { + ::CloseHandle(hFile); + } + ReleaseStr(pszData); + ReleaseStr(pwzFile); + + return hr; +} -- cgit v1.2.3-55-g6feb