From 7fe63cdb500fbab07ad5e0da8810639475aac9fb Mon Sep 17 00:00:00 2001 From: Andrey Nekrasov Date: Tue, 21 Sep 2021 15:15:59 +0300 Subject: [PATCH] [Setup] add support for embedded MSIX packages (#13263) --- .github/actions/spell-check/expect.txt | 5 +- .../bootstrapper/RcResource.cpp | 45 ------- .../bootstrapper/RcResource.h | 45 ++++++- .../bootstrapper/bootstrapper.cpp | 2 +- .../bootstrapper/bootstrapper.vcxproj | 1 - installer/PowerToysSetup/Product.wxs | 25 +++- .../CustomAction.cpp | 116 ++++++++++++++---- .../CustomAction.def | 2 + .../PowerToysSetupCustomActions.vcxproj | 12 +- ...owerToysSetupCustomActions.vcxproj.filters | 5 + .../PowerToysSetupCustomActions/Resource.rc | 61 +++++++++ .../PowerToysSetupCustomActions/resource.h | 16 +++ .../PowerToysSetupCustomActions/stdafx.h | 6 + 13 files changed, 263 insertions(+), 78 deletions(-) delete mode 100644 installer/PowerToysBootstrapper/bootstrapper/RcResource.cpp create mode 100644 installer/PowerToysSetupCustomActions/Resource.rc create mode 100644 installer/PowerToysSetupCustomActions/resource.h diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 202a710ee..20a5a74dd 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -12,10 +12,10 @@ Acceleratorkeys ACCEPTFILES accessibile accessibilityinsights +Accessible Acl aclapi AColumn -Accessible acos acrt Actioncenter @@ -126,8 +126,8 @@ AUTOMATIONPROPERTIES Autorun AUTOSIZECOLUMNS AUTOUPDATE -AValid available +AValid awakeversion AWAYMODE AYUV @@ -1321,6 +1321,7 @@ msiquery MSIRESTARTMANAGERCONTROL msix msixbundle +MSIXCA MSIXVERSION MSLLHOOKSTRUCT Mso diff --git a/installer/PowerToysBootstrapper/bootstrapper/RcResource.cpp b/installer/PowerToysBootstrapper/bootstrapper/RcResource.cpp deleted file mode 100644 index d4214446e..000000000 --- a/installer/PowerToysBootstrapper/bootstrapper/RcResource.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "pch.h" -#include "RcResource.h" - -#include - -std::optional RcResource::create(int resource_id, const std::wstring_view resource_class) -{ - const HRSRC resHandle = FindResourceW(nullptr, MAKEINTRESOURCEW(resource_id), resource_class.data()); - if (!resHandle) - { - return std::nullopt; - } - - const HGLOBAL memHandle = LoadResource(nullptr, resHandle); - if (!memHandle) - { - return std::nullopt; - } - - const size_t resSize = SizeofResource(nullptr, resHandle); - if (!resSize) - { - return std::nullopt; - } - - auto res = static_cast(LockResource(memHandle)); - if (!res) - { - return std::nullopt; - } - - return RcResource{ res, resSize }; -} - -bool RcResource::saveAsFile(const std::filesystem::path destination) -{ - std::fstream installerFile{ destination, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc }; - if (!installerFile.is_open()) - { - return false; - } - - installerFile.write(reinterpret_cast(_memory), _size); - return true; -} diff --git a/installer/PowerToysBootstrapper/bootstrapper/RcResource.h b/installer/PowerToysBootstrapper/bootstrapper/RcResource.h index 120639ebb..aabbb532b 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/RcResource.h +++ b/installer/PowerToysBootstrapper/bootstrapper/RcResource.h @@ -3,6 +3,9 @@ #include #include #include +#include + +#include class RcResource { @@ -10,8 +13,46 @@ public: const std::byte* _memory = nullptr; size_t _size = 0; - static std::optional create(int resource_id, const std::wstring_view resource_class); - bool saveAsFile(const std::filesystem::path destination); + static inline std::optional create(int resource_id, const std::wstring_view resource_class, const HINSTANCE handle = nullptr) + { + const HRSRC resHandle = FindResourceW(handle, MAKEINTRESOURCEW(resource_id), resource_class.data()); + if (!resHandle) + { + return std::nullopt; + } + + const HGLOBAL memHandle = LoadResource(handle, resHandle); + if (!memHandle) + { + return std::nullopt; + } + + const size_t resSize = SizeofResource(handle, resHandle); + if (!resSize) + { + return std::nullopt; + } + + auto res = static_cast(LockResource(memHandle)); + if (!res) + { + return std::nullopt; + } + + return RcResource{ res, resSize }; + } + + inline bool saveAsFile(const std::filesystem::path destination) + { + std::fstream installerFile{ destination, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc }; + if (!installerFile.is_open()) + { + return false; + } + + installerFile.write(reinterpret_cast(_memory), _size); + return true; + } private: RcResource() = delete; diff --git a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp index 571777adb..760002e9f 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp +++ b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp @@ -392,7 +392,7 @@ int Bootstrapper(HINSTANCE hInstance) if (!package_path.empty() && !uninstall_msi_version(package_path)) { - spdlog::error("Couldn't install the existing MSI package ({})", GetLastError()); + spdlog::error("Couldn't uninstall the existing MSI package ({})", GetLastError()); ShowMessageBoxError(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR); return 1; } diff --git a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.vcxproj b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.vcxproj index c721342d6..e1417ef73 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.vcxproj +++ b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.vcxproj @@ -119,7 +119,6 @@ Create - diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 6931d60ba..40f13e744 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -94,13 +94,20 @@ + + NOT Installed Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL") - + + @@ -133,7 +140,21 @@ DllEntry="RemoveScheduledTasksCA" /> - + + + + #include "../../src/common/utils/MsiUtils.h" #include "../../src/common/updating/installer.h" #include "../../src/common/version/version.h" +#include "../../installer/PowerToysBootstrapper/bootstrapper/RcResource.h" + using namespace std; +HINSTANCE DLL_HANDLE = nullptr; + TRACELOGGING_DEFINE_PROVIDER( g_hProvider, "Microsoft.PowerToysInstaller", @@ -21,6 +25,78 @@ const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0' static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}"; static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}"; +UINT __stdcall InstallEmbeddedMSIXCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + hr = WcaInitialize(hInstall, "InstallEmbeddedMSIXCA"); + ExitOnFailure(hr, "Failed to initialize"); + + if (auto msix = RcResource::create(IDR_BIN_MSIX_HELLO_PACKAGE, L"BIN", DLL_HANDLE)) + { + WcaLog(LOGMSG_STANDARD, "Extracted MSIX"); + // TODO: Use to activate embedded MSIX + const auto msix_path = std::filesystem::temp_directory_path() / "hello_package.msix"; + if (!msix->saveAsFile(msix_path)) + { + ExitOnFailure(hr, "Failed to save msix"); + } + WcaLog(LOGMSG_STANDARD, "Saved MSIX"); + using namespace winrt::Windows::Management::Deployment; + using namespace winrt::Windows::Foundation; + + Uri msix_uri{ msix_path.wstring() }; + PackageManager pm; + auto result = pm.AddPackageAsync(msix_uri, nullptr, DeploymentOptions::None).get(); + if (!result) + { + ExitOnFailure(hr, "Failed to AddPackage"); + } + + WcaLog(LOGMSG_STANDARD, "MSIX[s] were installed!"); + } + else + { + ExitOnFailure(hr, "Failed to extract msix"); + } + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + +UINT __stdcall UninstallEmbeddedMSIXCA(MSIHANDLE hInstall) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + using namespace winrt::Windows::Management::Deployment; + using namespace winrt::Windows::Foundation; + // TODO: This must be replaced with the actual publisher and package name + const wchar_t package_name[] = L"46b35c25-b593-48d5-aeb1-d3e9c3b796e9"; + const wchar_t publisher[] = L"CN=yuyoyuppe"; + PackageManager pm; + + hr = WcaInitialize(hInstall, "UninstallEmbeddedMSIXCA"); + ExitOnFailure(hr, "Failed to initialize"); + + for (const auto& p : pm.FindPackagesForUser({}, package_name, publisher)) + { + auto result = pm.RemovePackageAsync(p.Id().FullName()).get(); + if (result) + { + WcaLog(LOGMSG_STANDARD, "MSIX was uninstalled!"); + } + else + { + WcaLog(LOGMSG_STANDARD, "Couldn't uninstall MSIX!"); + } + } + +LExit: + er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; + return WcaFinalize(er); +} + // Creates a Scheduled Task to run at logon for the current user. // The path of the executable to run should be passed as the CustomActionData (Value). // Based on the Task Scheduler Logon Trigger Example: @@ -42,12 +118,12 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) ITaskSettings* pSettings = nullptr; ITriggerCollection* pTriggerCollection = nullptr; IRegisteredTask* pRegisteredTask = nullptr; - IPrincipal * pPrincipal = nullptr; - ITrigger * pTrigger = nullptr; - ILogonTrigger * pLogonTrigger = nullptr; - IAction * pAction = nullptr; - IActionCollection * pActionCollection = nullptr; - IExecAction * pExecAction = nullptr; + IPrincipal* pPrincipal = nullptr; + ITrigger* pTrigger = nullptr; + ILogonTrigger* pLogonTrigger = nullptr; + IAction* pAction = nullptr; + IActionCollection* pActionCollection = nullptr; + IExecAction* pExecAction = nullptr; LPWSTR wszExecutablePath = nullptr; @@ -190,7 +266,6 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall) pActionCollection->Release(); ExitOnFailure(hr, "Cannot create the action: %x", hr); - // QI for the executable task pointer. hr = pAction->QueryInterface( IID_IExecAction, (void**)&pExecAction); @@ -302,7 +377,7 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall) ITaskService* pService = nullptr; ITaskFolder* pTaskFolder = nullptr; IRegisteredTaskCollection* pTaskCollection = nullptr; - ITaskFolder * pRootFolder = nullptr; + ITaskFolder* pRootFolder = nullptr; LONG numTasks = 0; hr = WcaInitialize(hInstall, "RemoveScheduledTasksCA"); @@ -589,9 +664,8 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall) MsiSetPropertyW(hInstall, L"INSTALLFOLDER", install_path->data()); } } - catch(...) + catch (...) { - } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); @@ -609,7 +683,7 @@ UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall) HCERTSTORE hCertStore = nullptr; HANDLE hfile = nullptr; DWORD size = INVALID_FILE_SIZE; - char * pFileContent = nullptr; + char* pFileContent = nullptr; hr = WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA"); ExitOnFailure(hr, "Failed to initialize", hr); @@ -648,11 +722,11 @@ UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall) } if (!CertAddEncodedCertificateToStore(hCertStore, - X509_ASN_ENCODING, - (const BYTE*)pFileContent, - size, - CERT_STORE_ADD_ALWAYS, - nullptr)) + X509_ASN_ENCODING, + (const BYTE*)pFileContent, + size, + CERT_STORE_ADD_ALWAYS, + nullptr)) { hr = GetLastError(); ExitOnFailure(hr, "Adding certificate failed", hr); @@ -678,13 +752,11 @@ LExit: MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord); } - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); #endif } - UINT __stdcall InstallVirtualCameraDriverCA(MSIHANDLE hInstall) { HRESULT hr = S_OK; @@ -793,7 +865,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall) } wchar_t processName[MAX_PATH] = L""; - HANDLE hProcess{OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, procID)}; + HANDLE hProcess{ OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, procID) }; if (!hProcess) { continue; @@ -819,7 +891,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall) GetWindowThreadProcessId(hwnd, &windowProcID); if (windowProcID == targetProcID) { - DWORD_PTR _ {}; + DWORD_PTR _{}; SendMessageTimeoutA(hwnd, WM_CLOSE, 0, 0, SMTO_BLOCK, timeout, &_); } return TRUE; @@ -837,7 +909,6 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall) return WcaFinalize(er); } - // DllMain - Initialize and cleanup WiX custom action utils. extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID) { @@ -846,6 +917,7 @@ extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in L case DLL_PROCESS_ATTACH: WcaGlobalInitialize(hInst); TraceLoggingRegister(g_hProvider); + DLL_HANDLE = hInst; break; case DLL_PROCESS_DETACH: diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def index 06383fb65..c72095544 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.def +++ b/installer/PowerToysSetupCustomActions/CustomAction.def @@ -16,4 +16,6 @@ EXPORTS TerminateProcessesCA CertifyVirtualCameraDriverCA InstallVirtualCameraDriverCA + InstallEmbeddedMSIXCA UninstallVirtualCameraDriverCA + UninstallEmbeddedMSIXCA \ No newline at end of file diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj index 6ad2af8a1..07c14882c 100644 --- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj +++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj @@ -15,7 +15,7 @@ {32f3882b-f2d6-4586-b5ed-11e39e522bd3} Win32Proj PowerToysSetupCustomActions - 10.0.17134.0 + 10.0.18362.0 @@ -53,10 +53,11 @@ inc;..\..\src\;telemetry;$(WIX)sdk\$(WixPlatformToolset)\inc;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\inc;%(AdditionalIncludeDirectories) + /await /Zc:twoPhase- /Wv:18 %(AdditionalOptions) $(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;..\..\$(PlatformShortName)\$(Configuration)\;%(AdditionalLibraryDirectories) - Newdev.lib;Crypt32.lib;msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies) + WindowsApp.lib;Newdev.lib;Crypt32.lib;msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies) @@ -112,10 +113,15 @@ + + + + + @@ -124,4 +130,4 @@ - + \ No newline at end of file diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters index a9e2292c5..85074f6e1 100644 --- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters +++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj.filters @@ -12,6 +12,8 @@ Telemetry + + @@ -22,4 +24,7 @@ {6e73ce5d-e715-4e7e-b796-c5d180b07ff2} + + + \ No newline at end of file diff --git a/installer/PowerToysSetupCustomActions/Resource.rc b/installer/PowerToysSetupCustomActions/Resource.rc new file mode 100644 index 000000000..2b2dd4d7a --- /dev/null +++ b/installer/PowerToysSetupCustomActions/Resource.rc @@ -0,0 +1,61 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE 25, 1 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + +// TODO: Use to activate embedded MSIX +//IDR_BIN_MSIX_HELLO_PACKAGE BIN "..\\..\..\\src\\modules\\HelloModule\\AppPackages\\HelloModule_1.0.0.0_x64_Test\\HelloModule_1.0.0.0_x64.msix" + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/installer/PowerToysSetupCustomActions/resource.h b/installer/PowerToysSetupCustomActions/resource.h new file mode 100644 index 000000000..889117b7a --- /dev/null +++ b/installer/PowerToysSetupCustomActions/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Resource.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif + +#define IDR_BIN_MSIX_HELLO_PACKAGE 101 diff --git a/installer/PowerToysSetupCustomActions/stdafx.h b/installer/PowerToysSetupCustomActions/stdafx.h index 61a313486..7d80cbe2a 100644 --- a/installer/PowerToysSetupCustomActions/stdafx.h +++ b/installer/PowerToysSetupCustomActions/stdafx.h @@ -27,3 +27,9 @@ #include #include #include + +#include +#include +#include +#include +#include