diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 5dbd6fafa0..6be388004b 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -206,6 +206,7 @@ CANRENAME Captureascreenshot CAPTURECHANGED CASESENSITIVE +cassert CAtl CCDDEE ccf @@ -1010,7 +1011,6 @@ IRepository IResult ISavable isbi -iss ISearch IService isetting @@ -1019,6 +1019,7 @@ IShell ISingle ISmart isocpp +iss IStorage IStream istreambuf @@ -1029,9 +1030,9 @@ ITab ITask ITemplate ITEMSTATEICONCLICK +ITerminal ITest ith -ITerminal IThrottled IThumbnail ITrigger @@ -1342,6 +1343,7 @@ msedge MSGFLT mshtmdid msi +msiexec MSIFASTINSTALL MSIHANDLE MSIINSTALLER diff --git a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp index 42e17afe8c..eace67434e 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp +++ b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp @@ -165,6 +165,51 @@ std::optional get_installed_powertoys_version() }; } +void ReLaunchElevatedAndExit() +{ + std::wstring params; + int nCmdArgs = 0; + LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs); + for (int i = 1; i < nCmdArgs; ++i) + { + if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos) + { + params += L'"'; + params += argList[i]; + params += L'"'; + } + else + { + params += argList[i]; + } + + if (i != nCmdArgs - 1) + { + params += L' '; + } + } + + const auto processHandle = run_elevated(argList[0], params.c_str()); + if (!processHandle) + { + spdlog::error("Couldn't restart elevated: ({})", GetLastError()); + return; + } + + if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0) + { + DWORD exitCode = 0; + GetExitCodeProcess(processHandle, &exitCode); + std::exit(exitCode); + } + else + { + spdlog::error("Elevated setup process timed out after 60m: ({})", GetLastError()); + TerminateProcess(processHandle, 0); + std::exit(1); + } +} + int Bootstrapper(HINSTANCE hInstance) { winrt::init_apartment(); @@ -299,7 +344,14 @@ int Bootstrapper(HINSTANCE hInstance) } } - // Setup MSI UI visibility and restart as elevated if required + // Always elevate bootstrapper process since it invokes msiexec multiple times, + // so we can avoid multiple UAC confirmations + if (!is_process_elevated()) + { + ReLaunchElevatedAndExit(); + } + + // Setup MSI UI visibility if (!noFullUI) { MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr); @@ -307,58 +359,7 @@ int Bootstrapper(HINSTANCE hInstance) if (g_Silent) { - if (is_process_elevated()) - { - MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr); - } - else - { - spdlog::debug("MSI doesn't support silent mode without elevation => restarting elevated"); - // MSI fails to run in silent mode due to a suppressed UAC w/o elevation, - // so we restart ourselves elevated with the same args - std::wstring params; - int nCmdArgs = 0; - LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs); - for (int i = 1; i < nCmdArgs; ++i) - { - if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos) - { - params += L'"'; - params += argList[i]; - params += L'"'; - } - else - { - params += argList[i]; - } - - if (i != nCmdArgs - 1) - { - params += L' '; - } - } - - const auto processHandle = run_elevated(argList[0], params.c_str()); - if (!processHandle) - { - spdlog::error("Couldn't restart elevated to enable silent mode! ({})", GetLastError()); - return 1; - } - - if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0) - { - DWORD exitCode = 0; - GetExitCodeProcess(processHandle, &exitCode); - return exitCode; - } - else - { - spdlog::error("Elevated setup process timed out after 60m => using basic MSI UI ({})", GetLastError()); - // Couldn't install using the completely silent mode in an hour, use basic UI. - TerminateProcess(processHandle, 0); - MsiSetInternalUI(INSTALLUILEVEL_BASIC, nullptr); - } - } + MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr); } // Try killing PowerToys and prevent future processes launch by acquiring app mutex diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp index 7c7eb34038..f1b43265e5 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.cpp +++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp @@ -52,11 +52,11 @@ UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize"); hr = getInstallFolder(hInstall, installationFolder); ExitOnFailure(hr, "Failed to get installfolder."); - for (const auto& changeset : getAllModulesChangesets(installationFolder, false)) + for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false)) { - if (!changeset.apply()) + if (!changeSet.apply()) { - WcaLog(LOGMSG_STANDARD, "Couldn't apply registry changeset"); + WcaLog(LOGMSG_STANDARD, "Couldn't apply registry changeSet"); } } @@ -77,9 +77,9 @@ UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall) ExitOnFailure(hr, "Failed to initialize"); hr = getInstallFolder(hInstall, installationFolder); ExitOnFailure(hr, "Failed to get installfolder."); - for (const auto& changeset : getAllModulesChangesets(installationFolder, false)) + for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false)) { - changeset.unapply(); + changeSet.unApply(); } ExitOnFailure(hr, "Failed to extract msix"); diff --git a/src/common/utils/modulesRegistry.h b/src/common/utils/modulesRegistry.h index 14d0c7e51e..60be46bc00 100644 --- a/src/common/utils/modulesRegistry.h +++ b/src/common/utils/modulesRegistry.h @@ -6,7 +6,7 @@ namespace fs = std::filesystem; -inline registry::Changeset getSvgPreviewHandlerChangset(const std::wstring installationDir, const bool perUser) +inline registry::ChangeSet getSvgPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser) { using namespace registry::shellex; return generatePreviewHandler(PreviewHandlerType::preview, @@ -22,7 +22,7 @@ inline registry::Changeset getSvgPreviewHandlerChangset(const std::wstring insta L".svg"); } -inline registry::Changeset getMdPreviewHandlerChangset(const std::wstring installationDir, const bool perUser) +inline registry::ChangeSet getMdPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser) { using namespace registry::shellex; return generatePreviewHandler(PreviewHandlerType::preview, @@ -36,7 +36,7 @@ inline registry::Changeset getMdPreviewHandlerChangset(const std::wstring instal L".md"); } -inline registry::Changeset getPdfPreviewHandlerChangset(const std::wstring installationDir, const bool perUser) +inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser) { using namespace registry::shellex; return generatePreviewHandler(PreviewHandlerType::preview, @@ -50,7 +50,7 @@ inline registry::Changeset getPdfPreviewHandlerChangset(const std::wstring insta L".pdf"); } -inline registry::Changeset getSvgThumbnailHandlerChangset(const std::wstring installationDir, const bool perUser) +inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser) { using namespace registry::shellex; return generatePreviewHandler(PreviewHandlerType::thumbnail, @@ -64,7 +64,7 @@ inline registry::Changeset getSvgThumbnailHandlerChangset(const std::wstring ins L".svg"); } -inline registry::Changeset getPdfThumbnailHandlerChangset(const std::wstring installationDir, const bool perUser) +inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser) { using namespace registry::shellex; return generatePreviewHandler(PreviewHandlerType::thumbnail, @@ -78,11 +78,11 @@ inline registry::Changeset getPdfThumbnailHandlerChangset(const std::wstring ins L".pdf"); } -inline std::vector getAllModulesChangesets(const std::wstring installationDir, const bool perUser) +inline std::vector getAllModulesChangeSets(const std::wstring installationDir, const bool perUser) { - return { getSvgPreviewHandlerChangset(installationDir, perUser), - getMdPreviewHandlerChangset(installationDir, perUser), - getPdfPreviewHandlerChangset(installationDir, perUser), - getSvgThumbnailHandlerChangset(installationDir, perUser), - getPdfThumbnailHandlerChangset(installationDir, perUser) }; + return { getSvgPreviewHandlerChangeSet(installationDir, perUser), + getMdPreviewHandlerChangeSet(installationDir, perUser), + getPdfPreviewHandlerChangeSet(installationDir, perUser), + getSvgThumbnailHandlerChangeSet(installationDir, perUser), + getPdfThumbnailHandlerChangeSet(installationDir, perUser) }; } \ No newline at end of file diff --git a/src/common/utils/registry.h b/src/common/utils/registry.h index 88af8b83e0..d0ebcb1879 100644 --- a/src/common/utils/registry.h +++ b/src/common/utils/registry.h @@ -114,7 +114,7 @@ namespace registry valueSize) == ERROR_SUCCESS; } - bool unapply() const + bool unApply() const { HKEY key{}; if (RegOpenKeyExW(scope, path.c_str(), 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) @@ -207,7 +207,7 @@ namespace registry } }; - struct Changeset + struct ChangeSet { std::vector changes; @@ -233,12 +233,12 @@ namespace registry return ok; } - bool unapply() const + bool unApply() const { bool ok = true; for (const auto& c : changes) { - ok = c.unapply() && ok; + ok = c.unApply() && ok; } return ok; } @@ -256,7 +256,7 @@ namespace registry thumbnail }; - inline registry::Changeset generatePreviewHandler(const PreviewHandlerType handlerType, + inline registry::ChangeSet generatePreviewHandler(const PreviewHandlerType handlerType, const bool perUser, std::wstring handlerClsid, std::wstring powertoysVersion, @@ -323,7 +323,7 @@ namespace registry changes.push_back({ scope, previewHandlerListPath, handlerClsid, displayName }); } - return registry::Changeset{ .changes = std::move(changes) }; + return registry::ChangeSet{ .changes = std::move(changes) }; } } } diff --git a/src/modules/previewpane/powerpreview/powerpreview.cpp b/src/modules/previewpane/powerpreview/powerpreview.cpp index f989ca8886..751be1f605 100644 --- a/src/modules/previewpane/powerpreview/powerpreview.cpp +++ b/src/modules/previewpane/powerpreview/powerpreview.cpp @@ -20,23 +20,23 @@ PowerPreviewModule::PowerPreviewModule() : const bool installPerUser = false; m_fileExplorerModules.push_back({ .settingName = L"svg-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION), - .registryChanges = getSvgPreviewHandlerChangset(installationDir, installPerUser) }); + .registryChanges = getSvgPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"md-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION), - .registryChanges = getMdPreviewHandlerChangset(installationDir, installPerUser) }); + .registryChanges = getMdPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"pdf-previewer-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_PDF_SETTINGS_DESCRIPTION), - .registryChanges = getPdfPreviewHandlerChangset(installationDir, installPerUser) }); + .registryChanges = getPdfPreviewHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"svg-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), - .registryChanges = getSvgThumbnailHandlerChangset(installationDir, installPerUser) }); + .registryChanges = getSvgThumbnailHandlerChangeSet(installationDir, installPerUser) }); m_fileExplorerModules.push_back({ .settingName = L"pdf-thumbnail-toggle-setting", .settingDescription = GET_RESOURCE_STRING(IDS_PDF_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION), - .registryChanges = getPdfThumbnailHandlerChangset(installationDir, installPerUser) }); + .registryChanges = getPdfThumbnailHandlerChangeSet(installationDir, installPerUser) }); try { @@ -133,7 +133,7 @@ void PowerPreviewModule::disable() { for (auto& fileExplorerModule : m_fileExplorerModules) { - fileExplorerModule.registryChanges.unapply(); + fileExplorerModule.registryChanges.unApply(); } } else @@ -197,7 +197,7 @@ void PowerPreviewModule::apply_settings(const PowerToysSettings::PowerToyValues& } // (Un)Apply registry changes depending on the new setting value - const bool updated = *toggle ? fileExplorerModule.registryChanges.apply() : fileExplorerModule.registryChanges.unapply(); + const bool updated = *toggle ? fileExplorerModule.registryChanges.apply() : fileExplorerModule.registryChanges.unApply(); if (updated) { diff --git a/src/modules/previewpane/powerpreview/powerpreview.h b/src/modules/previewpane/powerpreview/powerpreview.h index e3f65bde96..1819c45ca8 100644 --- a/src/modules/previewpane/powerpreview/powerpreview.h +++ b/src/modules/previewpane/powerpreview/powerpreview.h @@ -12,7 +12,7 @@ struct FileExplorerModule { std::wstring settingName; std::wstring settingDescription; - registry::Changeset registryChanges; + registry::ChangeSet registryChanges; }; // Implement the PowerToy Module Interface and all the required methods.