diff --git a/Installer/Setup/BundleInstaller/ProjectDefaults.wxi b/Installer/Setup/BundleInstaller/ProjectDefaults.wxi index 38b7b56f..dfa1f7ca 100644 --- a/Installer/Setup/BundleInstaller/ProjectDefaults.wxi +++ b/Installer/Setup/BundleInstaller/ProjectDefaults.wxi @@ -14,7 +14,7 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/tools/build-release.ps1 b/tools/build-release.ps1 index bb4f786b..9d9c55fa 100644 --- a/tools/build-release.ps1 +++ b/tools/build-release.ps1 @@ -135,6 +135,20 @@ function Rename-ExistingMsi { catch { throw "无法读取旧 MSI 的 ProductVersion:$legacyMsi。$($_.Exception.Message)" } + finally { + # Windows Installer COM objects keep the MSI open until every RCW is released. + foreach ($comObject in @($record, $view, $database, $installer)) { + if ($null -ne $comObject) { + [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($comObject) + } + } + $record = $null + $view = $null + $database = $null + $installer = $null + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + } if ([string]::IsNullOrWhiteSpace($oldVersion)) { throw "旧 MSI 未包含有效的 ProductVersion:$legacyMsi" @@ -145,7 +159,21 @@ function Rename-ExistingMsi { throw "旧 MSI 的版本化文件已存在,为避免覆盖而停止:$versionedMsi" } - Move-Item -LiteralPath $legacyMsi -Destination $versionedMsi + $moved = $false + for ($attempt = 1; $attempt -le 5; $attempt++) { + try { + Move-Item -LiteralPath $legacyMsi -Destination $versionedMsi -ErrorAction Stop + $moved = $true + break + } + catch [System.IO.IOException] { + if ($attempt -eq 5) { throw } + Start-Sleep -Milliseconds 500 + } + } + if (-not $moved) { + throw "无法移动旧 MSI:$legacyMsi" + } Write-Host " Archived existing MSI: $versionedMsi" -ForegroundColor DarkGray }