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/shellexecca.cpp | 271 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 src/ext/Util/ca/shellexecca.cpp (limited to 'src/ext/Util/ca/shellexecca.cpp') diff --git a/src/ext/Util/ca/shellexecca.cpp b/src/ext/Util/ca/shellexecca.cpp new file mode 100644 index 00000000..ea21d3bd --- /dev/null +++ b/src/ext/Util/ca/shellexecca.cpp @@ -0,0 +1,271 @@ +// 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" + +HRESULT ShellExec( + __in LPCWSTR wzTarget, + __in BOOL fUnelevated + ) +{ + HRESULT hr = S_OK; + LPWSTR sczWorkingDirectory = NULL; + + // a reasonable working directory (not the system32 default from MSI) is the directory where the target lives + hr = PathGetDirectory(wzTarget, &sczWorkingDirectory); + ExitOnFailure(hr, "failed to get directory for target: %ls", wzTarget); + + if (!DirExists(sczWorkingDirectory, NULL)) + { + ReleaseNullStr(sczWorkingDirectory); + } + + if (fUnelevated) + { + hr = ShelExecUnelevated(wzTarget, NULL, NULL, sczWorkingDirectory, SW_SHOWDEFAULT); + ExitOnFailure(hr, "ShelExecUnelevated failed with target %ls", wzTarget); + } + else + { + HINSTANCE hinst = ::ShellExecuteW(NULL, NULL, wzTarget, NULL, sczWorkingDirectory, SW_SHOWDEFAULT); + if (hinst <= HINSTANCE(32)) + { + LONG64 code = reinterpret_cast(hinst); + switch (code) + { + case ERROR_FILE_NOT_FOUND: + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + break; + case ERROR_PATH_NOT_FOUND: + hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + break; + case ERROR_BAD_FORMAT: + hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); + break; + case SE_ERR_ASSOCINCOMPLETE: + case SE_ERR_NOASSOC: + hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); + break; + case SE_ERR_DDEBUSY: + case SE_ERR_DDEFAIL: + case SE_ERR_DDETIMEOUT: + hr = HRESULT_FROM_WIN32(ERROR_DDE_FAIL); + break; + case SE_ERR_DLLNOTFOUND: + hr = HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); + break; + case SE_ERR_OOM: + hr = E_OUTOFMEMORY; + break; + case SE_ERR_ACCESSDENIED: + hr = E_ACCESSDENIED; + break; + default: + hr = E_FAIL; + } + + ExitOnFailure(hr, "ShellExec failed with return code %llu.", code); + } + } + + +LExit: + ReleaseStr(sczWorkingDirectory); + return hr; +} + +extern "C" UINT __stdcall WixShellExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + LPWSTR pwzTarget = NULL; + + hr = WcaInitialize(hInstall, "WixShellExec"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetFormattedProperty(L"WixShellExecTarget", &pwzTarget); + ExitOnFailure(hr, "failed to get WixShellExecTarget"); + + WcaLog(LOGMSG_VERBOSE, "WixShellExecTarget is %ls", pwzTarget); + + if (!pwzTarget || !*pwzTarget) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to get WixShellExecTarget"); + } + + hr = ShellExec(pwzTarget, FALSE); + ExitOnFailure(hr, "failed to launch target"); + +LExit: + ReleaseStr(pwzTarget); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +extern "C" UINT __stdcall WixUnelevatedShellExec( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + LPWSTR pwzTarget = NULL; + + hr = WcaInitialize(hInstall, "WixUnelevatedShellExec"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetFormattedProperty(L"WixUnelevatedShellExecTarget", &pwzTarget); + ExitOnFailure(hr, "failed to get WixUnelevatedShellExecTarget"); + + WcaLog(LOGMSG_VERBOSE, "WixUnelevatedShellExecTarget is %ls", pwzTarget); + + if (!pwzTarget || !*pwzTarget) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to get WixShellExecTarget"); + } + + hr = ShellExec(pwzTarget, TRUE); + ExitOnFailure(hr, "failed to launch target"); + +LExit: + ReleaseStr(pwzTarget); + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} + +// +// ExtractBinary extracts the data from the Binary table row with the given ID into a file. +// +HRESULT ExtractBinary( + __in LPCWSTR wzBinaryId, + __out BYTE** pbData, + __out DWORD* pcbData + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzSql = NULL; + PMSIHANDLE hView; + PMSIHANDLE hRec; + + // make sure we're not horked from the get-go + hr = WcaTableExists(L"Binary"); + if (S_OK != hr) + { + if (SUCCEEDED(hr)) + { + hr = E_UNEXPECTED; + } + ExitOnFailure(hr, "There is no Binary table."); + } + + ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null"); + ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string"); + + hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzBinaryId); + ExitOnFailure(hr, "Failed to allocate Binary table query."); + + hr = WcaOpenExecuteView(pwzSql, &hView); + ExitOnFailure(hr, "Failed to open view on Binary table"); + + hr = WcaFetchSingleRecord(hView, &hRec); + ExitOnFailure(hr, "Failed to retrieve request from Binary table"); + + hr = WcaGetRecordStream(hRec, 1, pbData, pcbData); + ExitOnFailure(hr, "Failed to read Binary.Data."); + +LExit: + ReleaseStr(pwzSql); + + return hr; +} + +extern "C" UINT __stdcall WixShellExecBinary( + __in MSIHANDLE hInstall + ) +{ + Assert(hInstall); + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + LPWSTR pwzBinary = NULL; + LPWSTR pwzFilename = NULL; + BYTE* pbData = NULL; + DWORD cbData = 0; + HANDLE hFile = INVALID_HANDLE_VALUE; + +#if 0 + ::MessageBoxA(0, "WixShellExecBinary", "-->> ATTACH HERE", MB_OK); +#endif + + hr = WcaInitialize(hInstall, "WixShellExecBinary"); + ExitOnFailure(hr, "failed to initialize"); + + hr = WcaGetFormattedProperty(L"WixShellExecBinaryId", &pwzBinary); + ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); + + WcaLog(LOGMSG_VERBOSE, "WixShellExecBinaryId is %ls", pwzBinary); + + if (!pwzBinary || !*pwzBinary) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "failed to get WixShellExecBinaryId"); + } + + // get temporary path for extracted file + StrAlloc(&pwzFilename, MAX_PATH); + ExitOnFailure(hr, "Failed to allocate temporary path"); + ::GetTempPathW(MAX_PATH, pwzFilename); + hr = ::StringCchCatW(pwzFilename, MAX_PATH, pwzBinary); + ExitOnFailure(hr, "Failed to append filename."); + + // grab the bits + hr = ExtractBinary(pwzBinary, &pbData, &cbData); + ExitOnFailure(hr, "failed to extract binary data"); + + // write 'em to the temp file + hFile = ::CreateFileW(pwzFilename, 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", pwzFilename); + } + + DWORD cbWritten = 0; + if (!::WriteFile(hFile, pbData, cbData, &cbWritten, NULL)) + { + ExitWithLastError(hr, "Failed to write data to new temp file: %ls", pwzFilename); + } + + // close it + ::CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; + + // and run it + hr = ShellExec(pwzFilename, FALSE); + ExitOnFailure(hr, "failed to launch target: %ls", pwzFilename); + +LExit: + ReleaseStr(pwzBinary); + ReleaseStr(pwzFilename); + ReleaseMem(pbData); + if (INVALID_HANDLE_VALUE != hFile) + { + ::CloseHandle(hFile); + } + + if (FAILED(hr)) + { + er = ERROR_INSTALL_FAILURE; + } + return WcaFinalize(er); +} -- cgit v1.2.3-55-g6feb