- tools/repair-ico.ps1: 检测并修复 ICO 帧偏移量未计目录长度的损坏模式 - assets/dsh.ico: 已修复(原文件偏移全错,.NET Icon 无法加载) - tools/dsh-app.ps1: 归档加固版托盘脚本(图标加载兜底) - tools/dsh-app.ps1.README.md: 修复记录 + UTF-8 BOM 踩坑
48 lines
2.0 KiB
PowerShell
48 lines
2.0 KiB
PowerShell
# repair-ico.ps1 - Fix broken ICO files whose frame offsets omit the directory size.
|
|
#
|
|
# Background: some generators write ICO frame offsets starting at 0 (not accounting
|
|
# for the 6 + count*16 directory), which makes .NET Framework System.Drawing.Icon
|
|
# throw "The operation completed successfully". This script detects that pattern
|
|
# and adds the directory length to every frame offset.
|
|
#
|
|
# Usage: powershell -NoProfile -ExecutionPolicy Bypass -File repair-ico.ps1 <file.ico> [more.ico ...]
|
|
# Each file is backed up as <file>.bak-<timestamp> before being rewritten.
|
|
|
|
param([Parameter(Mandatory=$true, Position=0)][string]$IcoPath)
|
|
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
foreach ($path in @($IcoPath)) {
|
|
$full = (Resolve-Path $path -ErrorAction SilentlyContinue).Path
|
|
if (-not $full -or -not (Test-Path $full)) { Write-Host "SKIP (not found): $path"; continue }
|
|
$bytes = [System.IO.File]::ReadAllBytes($full)
|
|
if ($bytes.Length -lt 22) { Write-Host "SKIP (too small): $path"; continue }
|
|
|
|
$count = [BitConverter]::ToUInt16($bytes, 4)
|
|
if ($count -lt 1 -or $count -gt 64) { Write-Host "SKIP (odd frame count $count): $path"; continue }
|
|
$dirLen = 6 + $count * 16
|
|
|
|
# Detect the broken pattern: first frame offset is 0 (points at the directory itself)
|
|
$off0 = [BitConverter]::ToUInt32($bytes, 6 + 12)
|
|
if ($off0 -ne 0) { Write-Host "OK (first offset=$off0, no fix needed): $path"; continue }
|
|
|
|
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
$bak = "$full.bak-$stamp"
|
|
Copy-Item $full $bak -Force
|
|
|
|
$b = [byte[]]$bytes.Clone()
|
|
for ($i = 0; $i -lt $count; $i++) {
|
|
$o = 6 + $i * 16 + 12
|
|
$v = [BitConverter]::ToUInt32($b, $o) + $dirLen
|
|
[BitConverter]::GetBytes($v).CopyTo($b, $o)
|
|
}
|
|
[System.IO.File]::WriteAllBytes($full, $b)
|
|
|
|
try {
|
|
$ic = [System.Drawing.Icon]::new($full)
|
|
$ok = "OK $($ic.Width)x$($ic.Height)"
|
|
$ic.Dispose()
|
|
} catch { $ok = "STILL FAILS: $($_.Exception.InnerException.Message)" }
|
|
Write-Host "FIXED: $full (backup $bak) verify: $ok"
|
|
}
|