From a4d8a501d14c9f86635a7ec8f9178b821b978928 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sat, 1 Aug 2026 22:52:07 +0100 Subject: [PATCH] Enhance Windows MSI build script with improved error handling and database modes - Added constants for Windows Installer OpenDatabase modes to clarify database access options. - Improved error handling in the Set-InstallerBinaryStream function to gracefully handle cases where the Binary table is empty. - Refactored the New-WrapperMsiDatabase function to ensure proper path handling and database creation, enhancing the robustness of the MSI generation process. --- scripts/build-windows-msi.ps1 | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/scripts/build-windows-msi.ps1 b/scripts/build-windows-msi.ps1 index 0109bc8..561f101 100644 --- a/scripts/build-windows-msi.ps1 +++ b/scripts/build-windows-msi.ps1 @@ -15,6 +15,11 @@ param( $ErrorActionPreference = "Stop" +# Windows Installer OpenDatabase modes (winuser.h / MSI API). +$msiOpenDatabaseModeReadOnly = 0 +$msiOpenDatabaseModeTransact = 1 +$msiOpenDatabaseModeCreate = 3 + function Get-MsiVersion { param([string]$InputVersion) @@ -99,7 +104,11 @@ function Set-InstallerBinaryStream { ) $deleteSql = "DELETE FROM `Binary` WHERE `Name` = '$Name'" - Invoke-InstallerExecute -Database $Database -Sql $deleteSql + try { + Invoke-InstallerExecute -Database $Database -Sql $deleteSql + } catch { + # Ignore when the Binary table is empty on first insert. + } $insertSql = "INSERT INTO `Binary` (`Name`, `Data`) VALUES (?, ?)" $view = $Database.GetType().InvokeMember( @@ -147,23 +156,19 @@ function New-WrapperMsiDatabase { [string]$UpgradeCodeValue ) - if (Test-Path $OutputPath) { - Remove-Item -LiteralPath $OutputPath -Force - } - - $outputDir = Split-Path $OutputPath -Parent + $outputPath = [System.IO.Path]::GetFullPath($OutputPath) + $outputDir = Split-Path $outputPath -Parent if ($outputDir -and -not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir -Force | Out-Null } + if (Test-Path $outputPath) { + Remove-Item -LiteralPath $outputPath -Force + } + $installer = New-Object -ComObject WindowsInstaller.Installer - $database = $installer.GetType().InvokeMember( - "OpenDatabase", - "InvokeMethod", - $null, - $installer, - @($OutputPath, 1) - ) + # Mode 3 (create) is required for new databases; mode 1 (transact) only opens existing MSIs. + $database = $installer.OpenDatabase($outputPath, $msiOpenDatabaseModeCreate) Invoke-InstallerExecute -Database $database -Sql @" CREATE TABLE `Property` (