fix(installer): keep the desktop shortcut on a machine-wide update; harden install-policy checks

This commit is contained in:
Jeremy
2026-10-27 12:01:39 +00:00
parent c39a0f3658
commit c1670d0aa5
4 changed files with 30 additions and 9 deletions
+7 -2
View File
@@ -28,6 +28,8 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install the pinned packaging toolchain
shell: pwsh
run: |
@@ -35,8 +37,11 @@ jobs:
dotnet tool install --tool-path $tools wix --version 5.0.2
if ($LASTEXITCODE -ne 0) { throw 'WiX installation failed.' }
$tools >> $env:GITHUB_PATH
& (Join-Path $tools 'wix.exe') extension add -g WixToolset.UI.wixext/5.0.2 WixToolset.Util.wixext/5.0.2
if ($LASTEXITCODE -ne 0) { throw 'WiX extension installation failed.' }
$policy = Get-Content -Raw -LiteralPath packaging/windows/install-policy.json | ConvertFrom-Json
foreach ($extension in @($policy.extensions)) {
& (Join-Path $tools 'wix.exe') extension add -g "WixToolset.$extension.wixext/5.0.2"
if ($LASTEXITCODE -ne 0) { throw "WiX extension $extension installation failed." }
}
- name: Build and check non-executable installer fixtures
shell: pwsh
run: ./packaging/windows/test-install-policy.ps1 -OutputDirectory (Join-Path $env:RUNNER_TEMP 'craft-install-policy-tests')
+10 -3
View File
@@ -122,9 +122,11 @@ try {
Set-SessionProperty $session 'CRAFT_USER_DIR' 'D:\Existing user app'
Set-SessionProperty $session 'CRAFT_MACHINE_DIR' 'E:\Existing machine app'
$action = if ($scope -eq '1') { 'CraftRestoreMachineFolder' } else { 'CraftRestoreUserFolder' }
if (-not $explicit) {
if ($session.DoAction($action) -ne 1) { throw 'Remembered-folder property action failed.' }
}
# Evaluate the compiled condition, so the test exercises it instead of calling the action directly.
$restore = @(Read-Rows $database ('SELECT `Condition` FROM `InstallExecuteSequence` WHERE `Action` = ''{0}''' -f $action) 1)[0]
$selected = $session.EvaluateCondition($restore[0]) -eq 1
if ($selected -eq [bool]$explicit) { throw "$action must run only when no folder was supplied (condition: $($restore[0]))." }
if ($selected -and $session.DoAction($action) -ne 1) { throw 'Remembered-folder property action failed.' }
$expected = if ($explicit) { $explicit } elseif ($scope -eq '1') { 'E:\Existing machine app' } else { 'D:\Existing user app' }
if ((Get-SessionProperty $session 'INSTALLFOLDER') -ne $expected) { throw 'Custom or remembered folder was not preserved.' }
}
@@ -145,6 +147,11 @@ try {
throw 'Silent updates must restore the folder before directory costing.'
}
}
foreach ($resolver in @('CraftUFromLegacyExe','CraftMFromLegacyExe')) {
if (-not ($execute['AppSearch'] -lt $execute[$resolver] -and $execute[$resolver] -lt $execute['LaunchConditions'])) {
throw 'Both legacy folder resolvers must run after AppSearch and before the launch checks.'
}
}
# Switching the first-page choice must reset BOTH properties, including a back-and-forth change.
$events = @(Read-Rows $database 'SELECT `Event`, `Argument`, `Condition`, `Ordering` FROM `ControlEvent` WHERE `Dialog_` = ''CraftScopeDlg'' AND `Control_` = ''Next'' ORDER BY `Ordering`' 4)
# Model the full-UI upgrade entry with an existing machine-wide copy. Run
+12 -3
View File
@@ -27,12 +27,21 @@
updates with /passive and no properties, so deleting the shortcut is the only way its
users can say no. A value given on the command line wins. -->
<Property Id="INSTALLDESKTOPSHORTCUT" Secure="yes" />
<Property Id="EXISTINGDESKTOPSHORTCUT">
<DirectorySearch Id="DesktopSearch" Path="[DesktopFolder]" Depth="0">
<!-- AppSearch runs before the full-UI scope page can choose Everyone, so [DesktopFolder] still
names the user's desktop then. Search both desktops and keep the one for the chosen scope. -->
<Property Id="EXISTINGDESKTOPSHORTCUT_USER">
<DirectorySearch Id="DesktopSearchUser" Path="[DesktopFolder]" Depth="0">
<FileSearch Name="PdfCraft.lnk" />
</DirectorySearch>
</Property>
<SetProperty Id="INSTALLDESKTOPSHORTCUT" Value="1" After="CraftLoadOption2U" Sequence="first" Condition="NOT INSTALLDESKTOPSHORTCUT AND (NOT WIX_UPGRADE_DETECTED OR EXISTINGDESKTOPSHORTCUT)" />
<Property Id="EXISTINGDESKTOPSHORTCUT_MACHINE">
<DirectorySearch Id="DesktopSearchMachine" Path="[%PUBLIC]\Desktop" Depth="0">
<FileSearch Name="PdfCraft.lnk" />
</DirectorySearch>
</Property>
<SetProperty Id="EXISTINGDESKTOPSHORTCUT" Action="CraftExistingMachineShortcut" Value="[EXISTINGDESKTOPSHORTCUT_MACHINE]" After="CraftLoadOption2U" Sequence="first" Condition="ALLUSERS = 1 AND EXISTINGDESKTOPSHORTCUT_MACHINE" />
<SetProperty Id="EXISTINGDESKTOPSHORTCUT" Action="CraftExistingUserShortcut" Value="[EXISTINGDESKTOPSHORTCUT_USER]" After="CraftExistingMachineShortcut" Sequence="first" Condition="ALLUSERS &lt;&gt; 1 AND EXISTINGDESKTOPSHORTCUT_USER" />
<SetProperty Id="INSTALLDESKTOPSHORTCUT" Value="1" After="CraftExistingUserShortcut" Sequence="first" Condition="NOT INSTALLDESKTOPSHORTCUT AND (NOT WIX_UPGRADE_DETECTED OR EXISTINGDESKTOPSHORTCUT)" />
<!-- The File Explorer menus: "Edit with PdfCraft" for PDF files (#682) and "Create PDF with
PdfCraft…" for images (#190). Each is on by default for a first install and has a property
to leave it out of unattended installs: INSTALLPDFCONTEXTMENU=0 (also a welcome-dialog
+1 -1
View File
@@ -38,7 +38,7 @@ foreach ($arch in $Architectures) {
$sources = @($policy.sources | ForEach-Object { Join-Path $PSScriptRoot $_ })
$msi = Join-Path $stage "$($policy.id)-NOT-INSTALLABLE.msi"
$extensions = @($policy.extensions | ForEach-Object { '-ext'; "WixToolset.$_.wixext" })
& wix build @sources -arch $arch -wx @extensions `
& wix build @sources -arch $arch @extensions `
-culture en-US -d 'Version=0.0.1' -d 'DisplayVersion=0.0.1-metadata-test' `
-d "BinDir=$stage" -d "IconPath=$(Join-Path $root $policy.icon)" `
-d "DocsDir=$(Join-Path $stage 'docs')" -d "ModelsDir=$(Join-Path $stage 'models')" `