From 14f36cb0f127a658c839a6f4b820888179919e4a Mon Sep 17 00:00:00 2001 From: Stefan Markovic Date: Wed, 8 Feb 2023 16:30:39 +0100 Subject: [PATCH] Separate upgrade codes for per machine and per user installation Move per machine check to bootstrapper Move all defines to common.wxs Fix CI --- .github/actions/spell-check/expect.txt | 182 ++++++++++++++++-- .../ci/templates/build-powertoys-steps.yml | 16 ++ installer/PowerToysSetup/Common.wxi | 18 +- installer/PowerToysSetup/PowerToys.wxs | 43 ++--- .../PowerToysBootstrapper.wixproj | 8 +- .../PowerToysSetup/PowerToysInstaller.wixproj | 16 +- installer/PowerToysSetup/Product.wxs | 16 +- installer/PowerToysSetup/generateFileList.ps1 | 9 +- .../CustomAction.cpp | 30 +-- .../CustomAction.def | 1 - src/Version.props | 2 +- src/common/updating/updating.cpp | 12 +- src/common/updating/updating.h | 1 + src/common/utils/MsiUtils.h | 6 +- 14 files changed, 254 insertions(+), 106 deletions(-) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index fecd00c623e..ca9ea61a174 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1,14 +1,27 @@ aaaa +AAAAEF +AAB +AABAD +AACB +AACD +AAD +AADF +abap +ABE abgr abi ABlocked ABOUTBOX Abug +ACA accctrl Acceleratorkeys ACCEPTFILES ACCESSDENIED accessibilityinsights +ACDB +ACFC +ACFF Acl aclapi AColumn @@ -24,7 +37,18 @@ adml admx advapi advfirewall +AEAA +AEAD +AECC +AED +AEE +AEEB +AFAE +AFAEFC +AFDA +AFE AFeature +AFFE AFFINETRANSFORM AFX AGGREGATABLE @@ -64,7 +88,6 @@ appium Applets Applicationcan applicationconfiguration -applicationconfiguration applicationframehost applog appmanifest @@ -118,15 +141,38 @@ Avanc awakeness awakeversion AYUV +azcli +azor backtracer +BAF bak Bashkortostan Bayan +BBE bbwe +BCA +BCB +BCCE +BCCEA bck +BDB +BDBAD +BDCC +BDDF +BDFB +BEAA +BEB +BEEAADF +BEEC +BEFA Belarus betadele betsegaw +BFC +BFDE +BFEB +BFF +BFFA BGR bgra bhid @@ -177,22 +223,42 @@ Buryatia BValue BYPOSITION bytearray +CABD Caiguna CALG callbackptr +cameligo Cangjie CANRENAME CAPTURECHANGED CAtl +CBA +CBB +CBF +CCCCDE cch CCom CContext +CDAC +CDBF +CDCE +CDD +CDE cdecl CDeclaration CDEF cdpx +CEAF +CEBAC +CEBD +CECB CENTERALIGN ceq +CFAADB +CFBBF +CFEE +CFFEE +CFFF cguid changecursor Changemove @@ -201,7 +267,6 @@ CHILDACTIVATE CHILDWINDOW Choibalsan chrdavis -chromaticities Chrzan CHT Chukotka @@ -237,7 +302,6 @@ CMONITORS cmpgt cmyk cne -Cng cnt Cocklebiddy coclass @@ -332,8 +396,10 @@ cyberrex CYSMICON CYVIRTUALSCREEN cziplib +DAA Dac dacl +DAF damienleroy Danmarkshavn DARKPURPLE @@ -345,18 +411,29 @@ Datavalue DATAW davidegiacometti Dayof +DBAE +DBB +DBBDA +DBDE Dbg Dbghelp DBLCLKS DBLEPSILON +DCAB DCapture DCBA +DCBC +DCCB +DCEFCB +DCF DCOM dcommon dcomp dcompi DComposition DCR +DDCDD +DDCE DDevice ddf DDxgi @@ -365,6 +442,7 @@ debian debugbreak DECLAR declspec +DED Dedup DEFAULTBOOTSTRAPPERINSTALLFOLDER DEFAULTCOLOR @@ -385,7 +463,6 @@ Deondre depersist deprioritized depsfileslistspath -depsjsonpath deref DESKTOPABSOLUTEEDITING DESKTOPABSOLUTEPARSING @@ -398,6 +475,9 @@ devenum DEVMON devpkey DEVSOURCE +DFAB +DFB +DFBEA DIIRFLAG dimm directshow @@ -461,13 +541,41 @@ dxgi dxgidebug dxgiformat dxguid +EAAFE +EABF +EAC +EADC +EAF +EBCF +EBD +EBE +ecl ecount EData +EDB +EDCCC +EDFAE Edid +edis EDITKEYBOARD editkeyboardwindow EDITSHORTCUTS editshortcutswindow +edshift +EEA +EEB +EEBBE +EEBD +EED +EEDA +EEEE +EEF +EEFA +EFB +EFC +EFDD +EFE +EFFEFC EFile ekus emmintrin @@ -492,6 +600,7 @@ ERRORTITLE ESettings esize esrp +estructuredtext Eswatini etl etw @@ -525,15 +634,46 @@ exstyle EXTENDEDKEY EXTENDEDVERBS eyetracker +FABC fabricbot +FAEDDA +FAF +FAFD fancyzones FANCYZONESDRAWLAYOUTTEST FANCYZONESEDITOR Farbraum Faroe FARPROC +FBB +FBC +FBDE +FBF +FCAE +FCB +FCCFF +FCD +FCDB +FCDD +FCE +FDB +FDBF +FDC +FDCD +FDE +FDEF +FDF fdw +FECF +FEDF +FEEF feimage +FFB +FFBCF +FFBE +FFDDD +FFEB +FFEBEF fff fileapi FILEEXPLORER @@ -604,6 +744,7 @@ GNumber google gpo gpu +graphql GSM gtm gui @@ -778,6 +919,7 @@ INSTALLFOLDERTOPREVIOUSINSTALLFOLDER INSTALLLOCATION INSTALLMESSAGE INSTALLPROPERTY +installscopeperuser INSTALLSTARTMENUSHORTCUT INSTALLSTATE Inste @@ -792,7 +934,6 @@ ipcmanager IPlugin IPower IPREVIEW -IPREVIEW ipreviewhandler ipreviewhandlervisualssetfont IProperty @@ -825,11 +966,13 @@ JPN jpnime Jsons jsonval +julia junja jxr jyuwono KBDLLHOOKSTRUCT kbm +KCU KEYBDINPUT keyboardeventhandlers keyboardmanager @@ -853,6 +996,7 @@ KILLFOCUS killrunner Kitts Knownfolders +kotlin Krai KSPROPERTY Kwango @@ -886,6 +1030,7 @@ LError Lessthan LEVELID LExit +lexon lhs lhwnd LIBID @@ -904,7 +1049,6 @@ LMEM LMENU lnk LOADFROMFILE -LOADFROMFILE LOADLIBRARYASDATAFILE LOBYTE LOCALAPPDATA @@ -917,14 +1061,12 @@ logconsole logfile LOGFONT LOGFONTW -LOGFONTW LOGMSG logon LOGPIXELSX LOn longdate LONGLONG -louncher lowlevel LOWORD lparam @@ -986,8 +1128,6 @@ MAPTOSAMESHORTCUT MAPVK Markdig markdownpreviewhandler -markdownpreviewhandler -MARKDOWNPREVIEWHANDLERCPP MARKDOWNPREVIEWHANDLERCPP Markovic Marquesas @@ -1082,6 +1222,7 @@ msc msclr mscorlib msdata +msdax msedge MSGFLT MSIFASTINSTALL @@ -1106,6 +1247,7 @@ Mundrabilla mvvm myfile MYICON +mysql MYTZ NAMECHANGE nameof @@ -1154,6 +1296,7 @@ nielslaute NIF NLD nlog +nls NLSTEXT NOACTIVATE NOAGGREGATION @@ -1277,6 +1420,7 @@ PARENTRELATIVEPARSING PArgb parray PARTIALCONFIRMATIONDIALOGTITLE +pascaligo pathcch Pathto PAUDIO @@ -1302,6 +1446,7 @@ pfn pfo pft pgp +pgsql pguid PHANDLE PHANDLER @@ -1331,10 +1476,12 @@ Pohnpei Popups POPUPWINDOW posix +postiats poweraccent powerlauncher POWEROCR powerpreview +powerquery powerrename POWERRENAMECONTEXTMENU powerrenameinput @@ -1342,6 +1489,7 @@ POWERRENAMETEST powertoy POWERTOYNAME powertoyssetup +powertoysusersetup Powrprof ppidl ppmt @@ -1446,6 +1594,7 @@ RECTL rectp rects redirectedfrom +redis redist redistributable reencode @@ -1462,8 +1611,10 @@ REGFILTERPINS REGISTERCLASSFAILED registerhotkey registrypath +registryroot regkey REGPINTYPES +regroot regsvr reinit REINSTALLMODE @@ -1473,6 +1624,7 @@ remappings REMAPSUCCESSFUL REMAPUNSUCCESSFUL Remotable +Removedir Removelnk renamable RENAMEONCOLLISION @@ -1533,7 +1685,6 @@ rungameid RUNLEVEL runsettings runtimeclass -runtimeconfig runtimedepsjsonpath runtimeobject runtimepack @@ -1710,6 +1861,7 @@ stdcpplatest STDMETHODCALLTYPE STDMETHODIMP stefan +stefansjfw Stereolithography stgm STGMEDIUM @@ -1763,6 +1915,7 @@ SYSMENU SYSTEMAPPS systemroot SYSTEMTIME +systemverilog sysvol Tadele Tajikistan @@ -1783,6 +1936,7 @@ taskkill tasklist taskschd tchar +tcl Tcollab tcscpy TCustom @@ -1807,7 +1961,6 @@ THICKFRAME THISCOMPONENT THotkey thumbcache -thumbcache TILEDWINDOW timedate timediff @@ -1855,6 +2008,7 @@ UAC UAL uap uapmanifestschema +uby udit Udk Udmurtia @@ -1883,7 +2037,6 @@ Uniquifies unitconverter unittests Unk -Unk unknwn UNLEN Unmap @@ -2081,7 +2234,6 @@ wox wparam wpf wpfdepsjsonpath -wpfgfx wpftmp wpr wprp @@ -2116,6 +2268,7 @@ XBUTTONUP xcopy XDocument XElement +xfd XFile XIncrement XLoc @@ -2132,6 +2285,7 @@ yinle yinwang yinyue YOffset +ypescript YStr YUY yuyoyuppe diff --git a/.pipelines/ci/templates/build-powertoys-steps.yml b/.pipelines/ci/templates/build-powertoys-steps.yml index 1f6eab791ea..923778f8723 100644 --- a/.pipelines/ci/templates/build-powertoys-steps.yml +++ b/.pipelines/ci/templates/build-powertoys-steps.yml @@ -173,6 +173,22 @@ steps: clean: false maximumCpuCount: true +- task: PowerShell@2 + displayName: Clean installer dir before building per-user installer + inputs: + targetType: inline + script: git clean -xfd -e *exe -- .\installer\ + pwsh: true + +- task: NuGetCommand@2 + displayName: Restore NuGet packages for PowerToysSetup.sln + inputs: + command: restore + feedsToUse: config + configPath: NuGet.config + restoreSolution: installer\PowerToysSetup.sln + restoreDirectory: '$(Build.SourcesDirectory)\installer\packages' + - task: VSBuild@1 displayName: 'Build PowerToys per-user MSI' inputs: diff --git a/installer/PowerToysSetup/Common.wxi b/installer/PowerToysSetup/Common.wxi index 895a340df98..0acab7ae72a 100644 --- a/installer/PowerToysSetup/Common.wxi +++ b/installer/PowerToysSetup/Common.wxi @@ -17,23 +17,39 @@ + + + + + + + + + + - + + + + + + + diff --git a/installer/PowerToysSetup/PowerToys.wxs b/installer/PowerToysSetup/PowerToys.wxs index 682d3a8d034..c99e7a37c8f 100644 --- a/installer/PowerToysSetup/PowerToys.wxs +++ b/installer/PowerToysSetup/PowerToys.wxs @@ -1,33 +1,14 @@ - - - - - - - - - - - - - - - - - - - - - - - + + - + + + + - TargetPowerToysVersion >= DetectedPowerToysVersion OR WixBundleInstalled + + + + MinimumVersion >= DetectedPowerToysVersion + TargetPowerToysVersion >= DetectedPowerToysUserVersion OR WixBundleInstalled + + TargetPowerToysVersion >= DetectedPowerToysVersion OR WixBundleInstalled + @@ -90,7 +81,7 @@ diff --git a/installer/PowerToysSetup/PowerToysBootstrapper.wixproj b/installer/PowerToysSetup/PowerToysBootstrapper.wixproj index 725d1a1131d..ca716075950 100644 --- a/installer/PowerToysSetup/PowerToysBootstrapper.wixproj +++ b/installer/PowerToysSetup/PowerToysBootstrapper.wixproj @@ -26,10 +26,10 @@ PowerToysSetup-$(Version)-$(Platform) Bundle True - PowerToysSetup-$(Version)-$(Platform)-perMachine - PowerToysSetup-$(Version)-$(Platform)-perUser - $(Platform)\$(Configuration)\perMachine - $(Platform)\$(Configuration)\perUser + PowerToysSetup-$(Version)-$(Platform) + PowerToysUserSetup-$(Version)-$(Platform) + $(Platform)\$(Configuration)\MachineSetup + $(Platform)\$(Configuration)\UserSetup obj\$(Platform)\$(Configuration)\ diff --git a/installer/PowerToysSetup/PowerToysInstaller.wixproj b/installer/PowerToysSetup/PowerToysInstaller.wixproj index 6152b8b9930..be79c46186f 100644 --- a/installer/PowerToysSetup/PowerToysInstaller.wixproj +++ b/installer/PowerToysSetup/PowerToysInstaller.wixproj @@ -20,8 +20,8 @@ call "..\..\..\publish.cmd" x64 Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\ARM64\$(Configuration)\modules\FileExplorerPreview\monacoSRC IF NOT DEFINED IsPipeline ( call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=arm64 -host_arch=amd64 -winsdk=10.0.19041.0 -SET PTRoot=..\..\..\.. -call "..\..\publish.cmd" arm64 +SET PTRoot=..\..\..\..\.. +call "..\..\..\publish.cmd" arm64 ) @@ -70,8 +70,8 @@ call "..\..\publish.cmd" arm64 3.10 022a9d30-7c4f-416d-a9df-5ff2661cc0ad 2.0 - PowerToysSetup-$(Version)-$(Platform)-perMachine - PowerToysSetup-$(Version)-$(Platform)-perUser + PowerToysSetup-$(Version)-$(Platform) + PowerToysUserSetup-$(Version)-$(Platform) Package True @@ -82,10 +82,10 @@ call "..\..\publish.cmd" arm64 1026;1076 - $(Platform)\$(Configuration)\perMachine - $(Platform)\$(Configuration)\perUser - obj\$(Platform)\$(Configuration)\perMachine - obj\$(Platform)\$(Configuration)\perUser + $(Platform)\$(Configuration)\MachineSetup + $(Platform)\$(Configuration)\UserSetup + obj\$(Platform)\$(Configuration)\MachineSetup + obj\$(Platform)\$(Configuration)\UserSetup ICE40 diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 8d7d6c73954..adbd38c2483 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -23,17 +23,17 @@ Language="1033" Version="$(var.Version)" Manufacturer="Microsoft Corporation" - UpgradeCode="42B84BF7-5FBF-473B-9C8B-049DC16F7708"> + UpgradeCode="$(var.UpgradeCodeGUID)"> - + @@ -131,10 +131,9 @@ DEFAULTBOOTSTRAPPERINSTALLFOLDER OR PREVIOUSINSTALLFOLDER = ""]]> - + - @@ -389,13 +388,6 @@ DllEntry="DetectPrevInstallPathCA" /> - - { virtual void sink_it_(const spdlog::details::log_msg& msg) override @@ -755,38 +752,15 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall) UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, "DetectPrevInstallPathCA"); MsiSetPropertyW(hInstall, L"PREVIOUSINSTALLFOLDER", L""); - try - { - if (auto install_path = GetMsiPackageInstalledPath()) - { - MsiSetPropertyW(hInstall, L"PREVIOUSINSTALLFOLDER", install_path->data()); - } - } - catch (...) - { - } - er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; - return WcaFinalize(er); -} - -UINT __stdcall DetectPrevInstallScopeCA(MSIHANDLE hInstall) -{ - HRESULT hr = S_OK; - UINT er = ERROR_SUCCESS; - hr = WcaInitialize(hInstall, "DetectPrevInstallScopeCA"); LPWSTR currentScope = nullptr; hr = WcaGetProperty(L"InstallScope", ¤tScope); try { - auto install_scope = registry::install_scope::get_current_install_scope(); - if (install_scope == registry::install_scope::InstallScope::PerMachine && std::wstring{ currentScope } == L"perUser") + if (auto install_path = GetMsiPackageInstalledPath(std::wstring{ currentScope } == L"perUser")) { - PMSIHANDLE hRecord = MsiCreateRecord(0); - MsiRecordSetString(hRecord, 0, TEXT("PowerToys is already installed on this system for all users. We recommend first uninstalling that version before installing this one.'")); - MsiProcessMessage(hInstall, static_cast(INSTALLMESSAGE_ERROR + MB_OK), hRecord); - hr = E_FAIL; + MsiSetPropertyW(hInstall, L"PREVIOUSINSTALLFOLDER", install_path->data()); } } catch (...) diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def index 955eea5a29d..27d59b2fda7 100644 --- a/installer/PowerToysSetupCustomActions/CustomAction.def +++ b/installer/PowerToysSetupCustomActions/CustomAction.def @@ -10,7 +10,6 @@ EXPORTS CreateDotnetRuntimeHardlinksCA DeleteDotnetRuntimeHardlinksCA DetectPrevInstallPathCA - DetectPrevInstallScopeCA RemoveScheduledTasksCA TelemetryLogInstallSuccessCA TelemetryLogInstallCancelCA diff --git a/src/Version.props b/src/Version.props index 258a3316b56..6b54dbd99a6 100644 --- a/src/Version.props +++ b/src/Version.props @@ -1,7 +1,7 @@ - 0.68.1 + 0.0.1 Local diff --git a/src/common/updating/updating.cpp b/src/common/updating/updating.cpp index c196c10a2ea..800efd5d1fe 100644 --- a/src/common/updating/updating.cpp +++ b/src/common/updating/updating.cpp @@ -14,8 +14,8 @@ using namespace registry::install_scope; namespace // Strings in this namespace should not be localized { - const wchar_t LATEST_RELEASE_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/stefansjfw/latest"; - const wchar_t ALL_RELEASES_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/stefansjfw"; + const wchar_t LATEST_RELEASE_ENDPOINT[] = L"https://api.github.com/repos/stefansjfw/PowerToys/releases/latest"; + const wchar_t ALL_RELEASES_ENDPOINT[] = L"https://api.github.com/repos/stefansjfw/PowerToys/releases"; const wchar_t LOCAL_BUILD_ERROR[] = L"Local build cannot be updated"; const wchar_t NETWORK_ERROR[] = L"Network error"; @@ -45,15 +45,14 @@ namespace updating std::pair extract_installer_asset_download_info(const json::JsonObject& release_object) { const std::wstring_view required_architecture = get_architecture_string(get_current_architecture()); - constexpr const std::wstring_view required_filename_pattern = updating::INSTALLER_FILENAME_PATTERN; + std::wstring_view required_filename_pattern = updating::INSTALLER_FILENAME_PATTERN; // Desc-sorted by its priority const std::array asset_extensions = { L".exe", L".msi" }; const InstallScope current_install_scope = get_current_install_scope(); - std::wstring install_scope = L"permachine"; if (current_install_scope == InstallScope::PerUser) { - install_scope = L"peruser"; + required_filename_pattern = updating::INSTALLER_FILENAME_PATTERN_USER; } for (const auto asset_extension : asset_extensions) @@ -67,8 +66,7 @@ namespace updating const bool extension_matched = filename_lower.ends_with(asset_extension); const bool architecture_matched = filename_lower.find(required_architecture) != std::wstring::npos; const bool filename_matched = filename_lower.find(required_filename_pattern) != std::wstring::npos; - const bool scope_matched = filename_lower.find(install_scope) != std::wstring::npos; - const bool asset_matched = extension_matched && architecture_matched && filename_matched && scope_matched; + const bool asset_matched = extension_matched && architecture_matched && filename_matched; if (asset_matched) { return std::make_pair(Uri{ asset.GetNamedString(L"browser_download_url") }, std::move(filename_lower)); diff --git a/src/common/updating/updating.h b/src/common/updating/updating.h index a5a15e47de8..11ab3b95fd6 100644 --- a/src/common/updating/updating.h +++ b/src/common/updating/updating.h @@ -31,4 +31,5 @@ namespace updating // non-localized constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN = L"powertoyssetup"; + constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN_USER = L"powertoysusersetup"; } diff --git a/src/common/utils/MsiUtils.h b/src/common/utils/MsiUtils.h index 1489685005a..f369dd3b6f8 100644 --- a/src/common/utils/MsiUtils.h +++ b/src/common/utils/MsiUtils.h @@ -12,14 +12,16 @@ namespace // Strings in this namespace should not be localized { const inline wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}"; + const inline wchar_t POWER_TOYS_UPGRADE_CODE_USER[] = L"{D8B559DB-4C98-487A-A33F-50A8EEE42726}"; const inline wchar_t POWERTOYS_EXE_COMPONENT[] = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}"; } -std::optional GetMsiPackageInstalledPath() +std::optional GetMsiPackageInstalledPath(bool perUser) { constexpr size_t guid_length = 39; wchar_t product_ID[guid_length]; - if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(POWER_TOYS_UPGRADE_CODE, 0, 0, product_ID); !found) + std::wstring upgradeCode = (perUser ? POWER_TOYS_UPGRADE_CODE_USER : POWER_TOYS_UPGRADE_CODE); + if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(upgradeCode.c_str(), 0, 0, product_ID); !found) { return std::nullopt; }