Files
pauliusiv123-rgb 91c0b93c7f 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.
2026-10-13 00:09:56 -04:00

194 lines
17 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!--
PdfCraft MSI (WiX Toolset v5: `dotnet tool install -g wix`). Built by package.ps1:
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, 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.
-->
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package
Name="PdfCraft"
Manufacturer="Learning Machines LLC"
Version="$(var.Version)"
UpgradeCode="EA00C367-7270-4C50-9D8B-A7A5C88AD27F"
Scope="perMachine"
Compressed="yes"
Language="1033">
<SummaryInformation Description="PdfCraft PDF workbench" Manufacturer="Learning Machines LLC" />
<!-- HKLM registrations must never point into a per-user installation (#305). Allow removal
of an existing installation even if an older MSI let it install per-user. -->
<Launch Condition="ALLUSERS = 1 OR (Installed AND REMOVE = &quot;ALL&quot;)"
Message="PdfCraft must be installed for all users. Run setup with administrator privileges and ALLUSERS=1; per-user installation is not supported." />
<!-- Same-version upgrades let successive pre-releases of one X.Y.Z replace each other
(MSI versions are numeric, so 1.2.3-rc.1 and 1.2.3-rc.2 are both 1.2.3). -->
<MajorUpgrade AllowSameVersionUpgrades="yes"
DowngradeErrorMessage="A newer version of PdfCraft is already installed." />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<!-- Windows Installer requires an Icon id ending in .ico or .exe, or advertised shortcuts and
Add/Remove Programs show a blank icon (#57). -->
<Icon Id="PdfcraftIcon.ico" SourceFile="$(var.IconPath)" />
<Property Id="ARPPRODUCTICON" Value="PdfcraftIcon.ico" />
<Property Id="ARPURLINFOABOUT" Value="https://getartcraft.com/apps/pdfcraft" />
<Property Id="ARPURLUPDATEINFO" Value="https://getartcraft.com/apps/pdfcraft" />
<Property Id="ARPHELPLINK" Value="https://discord.gg/artcraft" />
<!-- Desktop shortcut (#143): on by default for a first install, a checkbox in the full-UI
welcome dialog, and INSTALLDESKTOPSHORTCUT=0 on the msiexec command line for unattended
installs. Secure, so the choice made in the (unelevated) UI reaches the elevated install.
An update keeps the shortcut only if it is still on the desktop (#1058): the launcher
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">
<FileSearch Name="PdfCraft.lnk" />
</DirectorySearch>
</Property>
<SetProperty Id="INSTALLDESKTOPSHORTCUT" Value="1" After="AppSearch" Sequence="first"
Condition="NOT INSTALLDESKTOPSHORTCUT AND (NOT WIX_UPGRADE_DETECTED OR EXISTINGDESKTOPSHORTCUT)" />
<!-- "Edit with PdfCraft" on the right-click menu of PDF files in File Explorer (#682): on by
default, the same way, and INSTALLPDFCONTEXTMENU=0 for unattended installs without it. -->
<Property Id="INSTALLPDFCONTEXTMENU" Value="1" Secure="yes" />
<UIRef Id="PdfcraftInstallerUI" />
<StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="INSTALLFOLDER" Name="PdfCraft">
<Directory Id="ModelsFolder" Name="models" />
</Directory>
</StandardDirectory>
<StandardDirectory Id="ProgramMenuFolder" />
<StandardDirectory Id="DesktopFolder" />
<Feature Id="Main" Title="PdfCraft" Level="1">
<ComponentGroupRef Id="PdfcraftFiles" />
<ComponentGroupRef Id="PdfcraftModels" />
</Feature>
</Package>
<Fragment>
<ComponentGroup Id="PdfcraftFiles" Directory="INSTALLFOLDER">
<Component Id="PdfcraftApp" Guid="E724C1C6-091F-4E21-A685-80D089FDBE21">
<File Id="PdfcraftExe" Source="$(var.BinDir)\pdfcraft.exe" KeyPath="yes" />
<RegistryValue Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\pdfcraft.exe" Value="[#PdfcraftExe]" Type="string" />
<!-- PDF files (#107): PdfCraft is offered under "Open with" and in Settings ▸ Default
apps, through Windows' Default Programs registration (a ProgID, OpenWithProgids,
Capabilities and RegisteredApplications). It never takes over an existing default:
.pdf's own default value is left alone, and the user chooses. Without this, the only
PdfCraft entry to pick was the advertised Start Menu shortcut, which Windows can't
run as a file handler ("This app can't run on your PC"). -->
<RegistryValue Root="HKLM" Key="Software\Classes\PdfCraft.Document" Value="PDF Document" Type="string" />
<!-- A negative index selects the stable icon resource ID, rather than its position.
Resource 1 is the app's lion; resource 2 is the PDF document (build.rs). -->
<RegistryValue Root="HKLM" Key="Software\Classes\PdfCraft.Document\DefaultIcon" Value="&quot;[#PdfcraftExe]&quot;,-2" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\PdfCraft.Document\shell\open\command" Value="&quot;[#PdfcraftExe]&quot; &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.pdf\OpenWithProgids" Name="PdfCraft.Document" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\pdfcraft.exe" Name="FriendlyAppName" Value="PdfCraft" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\pdfcraft.exe\DefaultIcon" Value="&quot;[#PdfcraftExe]&quot;,-2" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\pdfcraft.exe\SupportedTypes" Name=".pdf" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\pdfcraft.exe\shell\open\command" Value="&quot;[#PdfcraftExe]&quot; &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\PdfCraft\Capabilities" Name="ApplicationName" Value="PdfCraft" Type="string" />
<RegistryValue Root="HKLM" Key="Software\PdfCraft\Capabilities" Name="ApplicationDescription" Value="Open-source PDF workbench" Type="string" />
<RegistryValue Root="HKLM" Key="Software\PdfCraft\Capabilities" Name="ApplicationIcon" Value="[#PdfcraftExe],0" Type="string" />
<RegistryValue Root="HKLM" Key="Software\PdfCraft\Capabilities\FileAssociations" Name=".pdf" Value="PdfCraft.Document" Type="string" />
<RegistryValue Root="HKLM" Key="Software\RegisteredApplications" Name="PdfCraft" Value="Software\PdfCraft\Capabilities" Type="string" />
<!-- Image context menu (#190): convert without changing image file defaults. -->
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.png\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.png\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.png\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpg\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpg\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpg\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpeg\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpeg\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpeg\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.tif\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.tif\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.tif\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.tiff\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.tiff\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.tiff\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.gif\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.gif\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.gif\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.bmp\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.bmp\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.bmp\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jp2\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jp2\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jp2\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.j2k\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.j2k\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.j2k\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpx\shell\PdfCraft.CreatePdf" Value="Create PDF with PdfCraft…" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpx\shell\PdfCraft.CreatePdf" Name="MultiSelectModel" Value="Single" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.jpx\shell\PdfCraft.CreatePdf\command" Value="&quot;[#PdfcraftExe]&quot; --create-images &quot;%1&quot;" Type="string" />
</Component>
<!-- Shortcuts (#143) are plain links to pdfcraft.exe, not advertised MSI shortcuts: advertised
ones point at a Windows Installer descriptor rather than the program, which Windows can't
use as a file handler (#107), and 0.2.1's advertised one went missing from the Start menu
(#143). Each has its own component with an HKLM key path, so Windows Installer removes it
on uninstall; in this per-machine package both folders are the all-users ones. -->
<Component Id="PdfcraftStartMenuShortcut" Directory="ProgramMenuFolder" Guid="DC028192-C233-4F99-9A77-ED458C60DF26">
<Shortcut Id="StartMenuShortcut" Name="PdfCraft" Description="PdfCraft PDF workbench"
Target="[#PdfcraftExe]" WorkingDirectory="INSTALLFOLDER" Icon="PdfcraftIcon.ico" IconIndex="0" />
<RegistryValue Root="HKLM" Key="Software\PdfCraft\Shortcuts" Name="StartMenu" Type="integer" Value="1" KeyPath="yes" />
</Component>
<Component Id="PdfcraftDesktopShortcut" Directory="DesktopFolder" Guid="F6948627-32AB-4D78-8865-0FDF417CE442"
Condition="INSTALLDESKTOPSHORTCUT = 1">
<Shortcut Id="DesktopShortcut" Name="PdfCraft" Description="PdfCraft PDF workbench"
Target="[#PdfcraftExe]" WorkingDirectory="INSTALLFOLDER" Icon="PdfcraftIcon.ico" IconIndex="0" />
<RegistryValue Root="HKLM" Key="Software\PdfCraft\Shortcuts" Name="Desktop" Type="integer" Value="1" KeyPath="yes" />
</Component>
<!-- PDF context menu (#682): "Edit with PdfCraft" opens the file in PdfCraft whichever app is
the default for .pdf, which it leaves alone (SystemFileAssociations, like the image
menu). Several PDFs selected (up to 15, Windows' limit for this kind of entry) start one
launch each, and the single-instance hand-off opens them as tabs of one window. On
Windows 11 the entry is under "Show more options": the first-level menu only takes
packaged apps' (IExplorerCommand) entries. Its own component with an HKLM key path, so
INSTALLPDFCONTEXTMENU=0 leaves it out and uninstall removes it. -->
<Component Id="PdfcraftPdfContextMenu" Guid="439F084F-657D-4AC2-A4CC-F099C518D71F"
Condition="INSTALLPDFCONTEXTMENU = 1">
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.pdf\shell\PdfCraft.Edit" Value="Edit with PdfCraft" Type="string" KeyPath="yes" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.pdf\shell\PdfCraft.Edit" Name="Icon" Value="&quot;[#PdfcraftExe]&quot;,0" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.pdf\shell\PdfCraft.Edit" Name="MultiSelectModel" Value="Document" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\SystemFileAssociations\.pdf\shell\PdfCraft.Edit\command" Value="&quot;[#PdfcraftExe]&quot; &quot;%1&quot;" Type="string" />
</Component>
<Component Id="PdfcraftCli">
<File Id="PdfcraftCliExe" Source="$(var.BinDir)\pdfcraft-cli.exe" KeyPath="yes" />
</Component>
<!-- The embedded PDF icon's ISC notice and project licences travel with the binaries. -->
<Component Id="PdfcraftDocumentIconLicense">
<File Id="PdfcraftDocumentIconLicenseFile" Source="$(var.BinDir)\LICENSE-document.txt" KeyPath="yes" />
</Component>
<Component Id="PdfcraftMitLicense">
<File Id="PdfcraftMitLicenseFile" Source="$(var.BinDir)\LICENSE-MIT" KeyPath="yes" />
</Component>
<Component Id="PdfcraftApacheLicense">
<File Id="PdfcraftApacheLicenseFile" Source="$(var.BinDir)\LICENSE-APACHE" KeyPath="yes" />
</Component>
<Component Id="PdfcraftNotice">
<File Id="PdfcraftNoticeFile" Source="$(var.BinDir)\NOTICE" KeyPath="yes" />
</Component>
</ComponentGroup>
<!-- OCR models (#103), with their licences and ATTRIBUTION.txt, in models\ beside pdfcraft.exe
where the app looks for them: every file `cargo xtask models` fetched (package.ps1), one
component each, so new models ship without naming them here. -->
<ComponentGroup Id="PdfcraftModels" Directory="ModelsFolder">
<Files Include="$(var.ModelsDir)\*" />
</ComponentGroup>
</Fragment>
</Wix>