From 91c0b93c7fba5d78ea799132b5b3b3b163f7d4ac Mon Sep 17 00:00:00 2001 From: pauliusiv123-rgb <235694617+pauliusiv123-rgb@users.noreply.github.com> Date: Tue, 13 Oct 2026 07:09:56 +0300 Subject: [PATCH] Issue #1058: an update keeps the desktop shortcut only if it is still there (#1570) The launcher installs and updates PdfCraft with `msiexec /passive` and no properties, so INSTALLDESKTOPSHORTCUT always took its default of 1 and every update put the shortcut back, even for users who had deleted it. The property no longer has a static default: a SetProperty after AppSearch turns it on for a first install, and for an update only while PdfCraft.lnk is still on the all-users desktop. A value on the command line still wins, and the full-UI checkbox still starts ticked on a first install. test-msi.ps1 checks the action runs after AppSearch in both sequences and evaluates its condition for first installs, updates with and without the shortcut, and INSTALLDESKTOPSHORTCUT=0. --- docs/releasing.md | 8 ++++++-- packaging/windows/pdfcraft.wxs | 20 +++++++++++++++----- packaging/windows/test-msi.ps1 | 33 +++++++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/docs/releasing.md b/docs/releasing.md index 9576c4f13..5d6a850ab 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -121,7 +121,10 @@ neither the MSI nor the portable zip needs the Visual C++ redistributable. dialogs. Full UI confirms success with Finish; failures and cancellations have distinct messages. The welcome dialog has a "Create a desktop shortcut" checkbox and an "Edit with PdfCraft" right-click menu checkbox, both ticked by default. `/qn` and `/qb` stay unattended and create - both unless `INSTALLDESKTOPSHORTCUT=0` or `INSTALLPDFCONTEXTMENU=0` is passed. + both unless `INSTALLDESKTOPSHORTCUT=0` or `INSTALLPDFCONTEXTMENU=0` is passed. An update (the + launcher runs `msiexec /passive` with no properties) keeps the desktop shortcut only if + `PdfCraft.lnk` is still on the all-users desktop, so deleting it once keeps it away (#1058); a + value given on the command line wins. - The PDF right-click entry (#682) is a classic verb under `HKLM\Software\Classes\SystemFileAssociations\.pdf\shell\PdfCraft.Edit`, so it shows whichever app is the default for `.pdf` and never changes that default. Several selected PDFs (up to 15, the @@ -129,7 +132,8 @@ neither the MSI nor the portable zip needs the Visual C++ redistributable. hand-off opens them as tabs. On Windows 11 it is under "Show more options"; a first-level entry needs an `IExplorerCommand` handler and package identity (a sparse MSIX package), which the MSI doesn't have. -- `test-msi.ps1 ` checks the compiled shortcut, context-menu and dialog tables. Packaging +- `test-msi.ps1 ` checks the compiled shortcut, context-menu and dialog tables, and + evaluates the desktop shortcut's first-install and update conditions. Packaging runs it in a child process before signing, so the MSI isn't held open when signtool runs. The ARM64 install smoke test checks that both all-users shortcuts point at the installed `pdfcraft.exe` and are removed on uninstall, and that `INSTALLDESKTOPSHORTCUT=0` skips the desktop one. diff --git a/packaging/windows/pdfcraft.wxs b/packaging/windows/pdfcraft.wxs index e8bb53734..3f291721a 100644 --- a/packaging/windows/pdfcraft.wxs +++ b/packaging/windows/pdfcraft.wxs @@ -5,7 +5,7 @@ wix build pdfcraft.wxs installer-ui.wxs -arch x64 -d Version=1.2.3 -d BinDir=... -d ModelsDir=... -d IconPath=... -o out.msi Per-machine install into Program Files, a Start Menu shortcut, a desktop shortcut (on by default, - optional), an App Paths entry, PdfCraft registered as a PDF handler (offered under "Open with" + optional, and an update keeps it only if it is still there), an App Paths entry, PdfCraft registered as a PDF handler (offered under "Open with" and in Default apps, never forced as the default), and "Edit with PdfCraft" on PDF files' right-click menu (on by default, optional). Files opened with PdfCraft arrive on its command line. @@ -37,10 +37,20 @@ - - + + + + + + + + diff --git a/packaging/windows/test-msi.ps1 b/packaging/windows/test-msi.ps1 index 0b6fa7781..3af5bd037 100644 --- a/packaging/windows/test-msi.ps1 +++ b/packaging/windows/test-msi.ps1 @@ -74,7 +74,7 @@ Assert-Equal $status[0] 'Please wait while setup completes.' 'Persistent progres Assert-NoRow 'SELECT `Event` FROM `EventMapping` WHERE `Dialog_` = ''InstallProgress'' AND `Control_` = ''Status''' 'progress text subscription' # Plain (non-advertised) shortcuts to pdfcraft.exe, each in its own component; the desktop one is -# gated by INSTALLDESKTOPSHORTCUT, which defaults to 1 and is secure so the UI choice reaches the +# gated by INSTALLDESKTOPSHORTCUT, which is secure so the UI choice reaches the # elevated install. foreach ($entry in @(@('StartMenuShortcut', 'ProgramMenuFolder', 'PdfcraftStartMenuShortcut', ''), @('DesktopShortcut', 'DesktopFolder', 'PdfcraftDesktopShortcut', 'INSTALLDESKTOPSHORTCUT = 1'))) { @@ -88,8 +88,33 @@ foreach ($entry in @(@('StartMenuShortcut', 'ProgramMenuFolder', 'PdfcraftStartM Assert-Equal $component[0] $entry[1] "$($entry[2]) directory" Assert-Equal $component[1] $entry[3] "$($entry[2]) condition" } -$default = Read-Row 'SELECT `Value` FROM `Property` WHERE `Property` = ''INSTALLDESKTOPSHORTCUT''' 1 -Assert-Equal $default[0] '1' 'Desktop shortcut default' +# No static default (#1058): a SetProperty after AppSearch turns it on for a first install, and for an +# update only while the old shortcut is still on the desktop; a command-line value is left alone. +Assert-NoRow 'SELECT `Value` FROM `Property` WHERE `Property` = ''INSTALLDESKTOPSHORTCUT''' 'desktop shortcut static default' +$setDesktop = Read-Row 'SELECT `Action`, `Target` FROM `CustomAction` WHERE `Source` = ''INSTALLDESKTOPSHORTCUT''' 2 +Assert-Equal $setDesktop[1] '1' 'Desktop shortcut default value' +foreach ($sequence in @('InstallUISequence', 'InstallExecuteSequence')) { + $search = Read-Row ('SELECT `Sequence` FROM `' + $sequence + '` WHERE `Action` = ''AppSearch''') 1 + $set = Read-Row ('SELECT `Sequence`, `Condition` FROM `' + $sequence + '` WHERE `Action` = ''' + $setDesktop[0] + '''') 2 + if ([int] $set[0] -le [int] $search[0]) { throw "$sequence must set the desktop shortcut default after AppSearch" } +} +$session = $null +try { + $session = $Installer.OpenPackage((Resolve-Path -LiteralPath $Path).Path, 1) + foreach ($case in @( + @('first install', '', '', '', 1), + @('first install, INSTALLDESKTOPSHORTCUT=0', '0', '', '', 0), + @('update, shortcut still there', '', '{00000000-0000-0000-0000-000000000000}', 'C:\Users\Public\Desktop\PdfCraft.lnk', 1), + @('update, shortcut deleted', '', '{00000000-0000-0000-0000-000000000000}', '', 0), + @('update, INSTALLDESKTOPSHORTCUT=0', '0', '{00000000-0000-0000-0000-000000000000}', 'C:\Users\Public\Desktop\PdfCraft.lnk', 0))) { + $session.Property('INSTALLDESKTOPSHORTCUT') = $case[1] + $session.Property('WIX_UPGRADE_DETECTED') = $case[2] + $session.Property('EXISTINGDESKTOPSHORTCUT') = $case[3] + Assert-Equal ($session.EvaluateCondition($set[1])) $case[4] "Desktop shortcut default: $($case[0])" + } +} finally { + if ($session) { [void] [Runtime.InteropServices.Marshal]::FinalReleaseComObject($session) } +} $secure = Read-Row 'SELECT `Value` FROM `Property` WHERE `Property` = ''SecureCustomProperties''' 1 if (($secure[0] -split ';') -notcontains 'INSTALLDESKTOPSHORTCUT') { throw "INSTALLDESKTOPSHORTCUT is not secure: '$($secure[0])'" } $checkbox = Read-Row 'SELECT `Type`, `Property`, `Text` FROM `Control` WHERE `Dialog_` = ''InstallWelcome'' AND `Control` = ''DesktopShortcut''' 3 @@ -179,4 +204,4 @@ $rm = Read-Row 'SELECT `Dialog` FROM `Dialog` WHERE `Dialog` = ''MsiRMFilesInUse Assert-Equal $rm[0] 'MsiRMFilesInUse' 'Files-in-use dialog' [void] [Runtime.InteropServices.Marshal]::FinalReleaseComObject($Database) [void] [Runtime.InteropServices.Marshal]::FinalReleaseComObject($Installer) -Write-Output 'ok MSI: per-machine scope guard, publisher, persistent progress text, Start Menu shortcut, optional desktop shortcut (default on, checkbox), optional PDF context menu (default on, checkbox), icon/key path, full-UI success/cancel/error and Finish controls, files-in-use dialog, OCR models' +Write-Output 'ok MSI: per-machine scope guard, publisher, persistent progress text, Start Menu shortcut, optional desktop shortcut (on for a first install, kept on update only while present, checkbox), optional PDF context menu (default on, checkbox), icon/key path, full-UI success/cancel/error and Finish controls, files-in-use dialog, OCR models'