- 桌面应用
- 图像处理
【免费下载链接】ImageGlass
🏞 A fast, open-source, modern image viewer for 90+ formats – including WEBP, GIF, SVG, AVIF, JXL, HEIC and more – built for smooth browsing across Windows, macOS, and Linux.
导读
本指南基于 ImageGlass 仓库 source/__assets/win/README.md 及其配套打包脚本,系统讲解 Windows 端三套交付物的构建原理与实操:MSIX(Microsoft Store 与 GitHub sideload 两个风味)、MSI 安装器(WiX 5 双作用域)与便携版 ZIP。读完你将掌握三套 PowerShell 打包脚本的参数语义、签名与版本号策略、本地测试 Store 包的方法,以及 MSI 双作用域安装/升级中那些只有踩过坑才写得出的细节——每一条都能在仓库源码中找到对应实现。
三套交付物总览
ImageGlass 的 Windows 端由同一个ImageGlass.Win32自包含 AOT 构建派生出三种产物,全部产出到__artifacts/bundle/:
| 产物 | 用途 | 架构 | 打包脚本 |
|---|---|---|---|
| MSIX(msstore 风味,未签名) | Microsoft Store 提交 | x64 / arm64 | script-pack-win-msix.ps1 |
| MSIX(signed 风味,Authenticode 签名) | GitHub Releases sideload | x64 / arm64 | 同上(加-Sign) |
| MSI 安装器 | GitHub Releases 传统安装 | 仅 x64 | script-pack-win-msi.ps1 |
| 便携版 ZIP | GitHub Releases 免安装 | x64 / arm64 | script-pack-win-zip.ps1 |
MSIX 的两种风味差异集中在签名、身份(Identity)与美工三处:
| 风味 | 签名 | Identity / Publisher | 美工资源 | 去向 |
|---|---|---|---|---|
| msstore | 否(Store 提交时重签) | Store 保留名 + Publisher | Assets-msstore | Microsoft Store |
| signed | 是(每个.exe/.dll+ 包本身) | 普通名 + 证书 Subject | Assets-signed | GitHub Release |
微软商店在提交时自行重签包,所以msstore 构建必须保持未签名——如果你自己签了再上传,反而会被拒绝或出问题;而 GitHub 风味必须签名,因为未签名的 MSIX 无法安装。
环境准备(Prerequisites)
三套脚本统一要求PowerShell 7+(文件头均有#Requires -Version 7.0),以及以下工具链:
- Windows 10/11 SDK:提供
makeappx.exe、makepri.exe、signtool.exe。脚本中的Find-SdkTool会自动在Windows Kits\10\bin下按版本号排序选最新的一个,无需手工配置 PATH。 - .NET 10 SDK:用于
dotnet publish产出 Release、AOT、自包含的构建。 - 代码签名证书(仅 signed 风味):安装在
CurrentUser\My或LocalMachine\My并带私钥,或以 PFX 文件形式提供。 - WiX Toolset 5.0.2(仅 MSI):.NET 全局工具 + UI 扩展,安装命令如下,且版本被钉死:
dotnet tool install --global wix --version 5.0.2 wix extension add -g WixToolset.UI.wixext/5.0.2版本为何钉死?WiX 6/7 是同一工具在 FireGiant Open Source Maintenance Fee 许可下的续作,而裸
dotnet tool install --global wix会装最新的。script-pack-win-msi.ps1中的Assert-WixVersion会读取wix --version并严格比对5.0.2,不一致直接抛错并提示重装。加-BootstrapWix参数可让脚本代装钉死版本。
- 签名的 Pro 许可证(仅 msstore 风味):从官网管理后台签发一份
channel: msstore、versionScope: 10、initVersion: <当前版本>、无邮箱、无过期日的许可证,把下载的<licenseId>.iglicense.json放进 git 忽略的__artifacts\store-license\,或显式传-StoreLicenseFile。没有它 msstore 构建会立即失败(Resolve-StoreLicense在发布前就检查,避免几分钟后才失败)。
MSIX 打包实战
基础命令
# Microsoft Store(未签名) pwsh __assets/win/script-pack-win-msix.ps1 -Platform x64 pwsh __assets/win/script-pack-win-msix.ps1 -Platform arm64 # GitHub Release(签名;按证书 Subject 子串选择) pwsh __assets/win/script-pack-win-msix.ps1 -Platform x64 -Sign pwsh __assets/win/script-pack-win-msix.ps1 -Platform arm64 -Sign # 一个 .msixbundle 同时装下 x64 + arm64 pwsh __assets/win/script-pack-win-msix.ps1 -Bundle -Sign # 签名,给 GitHub pwsh __assets/win/script-pack-win-msix.ps1 -Bundle # 未签名,给 Store # 用 PFX 而非证书库签名 pwsh __assets/win/script-pack-win-msix.ps1 -Platform x64 -Sign -CertFile C:\ig.pfx -CertPassword <pw>也可在 VS Code 里通过任务运行:pack-win-x64-msix、pack-win-arm64-msix(GitHub 签名单架构包)、pack-win-msstore-msixbundle(Store 未签名双架构包)、pack-win-all(全部产物)。
输出命名规则为ImageGlass_<version>_win-x64.msix(或_win-arm64.msix,signed)与ImageGlass_<version>_win-msstore.msixbundle(msstore)。
完整参数表
| 参数 | 说明 | 默认值 |
|---|---|---|
-Platform | x64 或 arm64;-Bundle时忽略 | x64 |
-Bundle | 打包 x64+arm64 单一.msixbundle | 关 |
-Sign | signed 风味;无证书时仍产出未签名包并警告 | 关 |
-CertSubject | 从证书库按 Subject 子串选证书 | Duong Dieu Phap |
-CertFile/-CertPassword | PFX 路径与密码 | 空 |
-TimestampUrl | RFC-3161 时间戳服务器 | http://timestamp.sectigo.com |
-PackageVersion | 覆盖包版本 | 见下节 |
-MsStoreIdentityName | Store 保留身份名 | 9662DuongDieuPhap.ImageGlass |
-MsStorePublisher | Store 分配的 Publisher DN | CN=29F1B9EC-... |
-SideloadIdentityName | signed 风味身份名 | DuongDieuPhap.ImageGlass |
-PublisherDisplayName | 显示名 | Duong Dieu Phap |
-UnvirtualizedResources | 退出资源虚拟化(见下文) | 关 |
-StoreLicenseFile | msstore 内嵌许可证路径 | __artifacts\store-license\*.iglicense.json |
-SkipPublish | 复用__artifacts/publish/win-<arch>加快迭代 | 关 |
.msix 与 .msixbundle 的区别
.msixbundle把 x64 与 arm64 两个.msix打包在一起,Windows 安装时自动选择匹配当前设备的架构,因此发布一个文件即可。bundle 内部的单架构包只做了载荷签名(其中的.exe/.dll带信任链),不对包本身签名——只有.msixbundle这一个文件被签名。
版本号策略:两个风味各自约束
只有 Store 对版本号有限制,所以两个风味采用不同方案(源码见 script-pack-win-msix.ps1 的版本段):
- sideload(GitHub):原样携带
<IgVersion>,例如10.0.6.906,与 MSI 和“关于”框一致。 - msstore:Store 保留了第 4 段(revision),要求其为
0,所以打包为<Major>.<Minor>.<IgBundleBuild>.0,例如10.0.6+ 构建号906→10.0.906.0,丢弃 patch 段。两个值都来自 Directory.Build.props,可用-PackageVersion覆盖。
脚本中的Assert-PackageVersion还会预校验:MSIX 版本必须恰好 3~4 段、每段 0~65535、major 段非 0,防止畸形版本在 publish 几分钟后才被makeappx以晦涩错误打回。
升级陷阱:Windows 拒绝安装比已装版本旧的包,所以每个风味的版本必须逐版抬升。sideload 包最高到
10.0.6.906时,会以10.0.<build>.0形式发布,而新方案排在其下面,因此首个采用新方案的发布需要更高的 major/minor(或传一个高于10.0.906.0的-PackageVersion),否则老安装无法升级。
文件类型关联:两个风味截然不同
Windows 对包声明的每个类型都会取清单中的图标,优先级高于经典DefaultIcon注册,因此两个风味策略相反(见New-FileTypeAssociationXml):
- signed / sideload(
-UnvirtualizedResources):清单不声明任何关联,让应用自己的 HKCU 注册与_ext_icons目录负责图标。同时清单中写入<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>与rescap:Capability Name="unvirtualizedResources",退出资源虚拟化后经典注册才能真正落到 HKCU。 - msstore:该注册在虚拟化环境中不可见,因此为每种格式声明一条关联并带各自
uap:Logo。扩展名列表直接读取Const.IMAGE_FORMATS(Const.cs,当前约 70 种格式,含.webp、.avif、.heic、.jxl等),保证清单与应用永不脱节。关联的DisplayName(如ImageGlass WEBP File)需与Win32DefaultAppApi.GetFriendlyTypeName保持一致。
Export-ExtIconPngs会把_ext_icons里每个.ico的 256px PNG 帧按targetsize-16/32/48/96/256五种尺寸导出为 MRT 可解析的 PNG 变体;找不到精确尺寸帧时才用 GDI+ 缩放兜底。
打包流水线(脚本内部六个步骤)
New-MsixPackage的完整流程:publish(dotnet publishRelease/AOT/自包含 + 拷贝__assets/__app共享资源)→stage(ImageGlass\子目录 + 剔除*.pdb;msstore 额外写入_store\许可证;未开启-UnvirtualizedResources时删掉_ext_icons死重)→生成清单(模板替换 + UTF-8 BOM 写出)→签名载荷(signed 风味对所有.exe/.dll)→构建资源索引(makepri createconfig+makepri new,让无限定名的 Logo 正确解析到各 DPI 变体)→打包(makeappx pack;-Bundle时先各架构各打一个.msix再makeappx bundle)。最后对最终产物.msix/.msixbundle签名并用signtool verify /pa校验,然后清理 staging 中间目录。
本地测试 msstore 包:两条正路
msstore 产物故意不签名,而 Windows 拒绝安装未签名包,所以不能双击安装测试。不要试图把Publisher改成你自己的证书 Subject 来绕过——Windows 的包族名中的 publisher id 由该 DN 派生,Win32AppIdentity.IsMsStorePackage(Win32AppIdentity.cs)正是据此判断,这样测试出来的包会自报“不是 Store 安装”,Pro 不会解锁,测的是错的东西。
方案一:用 Store 的 Publisher Subject 自签(安装体验最接近真实):
$subject = 'CN=29F1B9EC-D220-4DC3-BEDB-01A9CCA51904' # 必须等于清单 Publisher $cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject $subject ` -CertStoreLocation Cert:\CurrentUser\My -FriendlyName 'ImageGlass msstore local test' ` -TextExtension @('2.5.29.19={text}') # 信任它以便安装(需管理员),然后签一份 COPY,绝不签你要上传的产物 Export-Certificate -Cert $cert -FilePath "$env:TEMP\ig-store-test.cer" | Out-Null Import-Certificate -FilePath "$env:TEMP\ig-store-test.cer" -CertStoreLocation Cert:\LocalMachine\TrustedPeople Copy-Item __artifacts\bundle\ImageGlass_*_win-msstore.msixbundle __artifacts\bundle\local-test.msixbundle signtool sign /fd SHA256 /sha1 $cert.Thumbprint __artifacts\bundle\local-test.msixbundle Add-AppxPackage __artifacts\bundle\local-test.msixbundle方案二:注册松散布局(无需证书,但需要开发者模式):
makeappx unbundle /p __artifacts\bundle\ImageGlass_<version>_win-msstore.msixbundle /d "$env:TEMP\igb" makeappx unpack /p "$env:TEMP\igb\ImageGlass-x64.msix" /d "$env:TEMP\igx" Add-AppxPackage -Register "$env:TEMP\igx\AppxManifest.xml"无论哪种方式,测试后检查:帮助菜单显示Manage Pro license、Pro 功能解锁、licensed-to 行显示内嵌许可证的customerName。结束后用Remove-AppxPackage卸载、删除签名副本,并从Cert:\CurrentUser\My与Cert:\LocalMachine\TrustedPeople移除测试证书。
美工资源的生成
两套 Logo 集由 script-generate-msix-assets.ps1 从单张源图渲染:Assets-signed由 logo_c_512.png 生成,Assets-msstore由 logo_p_512.png 生成(Store 身份本身即授予 Pro,故用 Pro 版 Logo)。脚本按-ReferenceDir中的文件名逐一镜像:Logo 名决定基准尺寸(Square150x150→150,Wide310x150→310×150,StoreLogo→50),targetsize-N覆盖为 N×N,scale-N按基准缩放,Wide 系列居中绘制在透明宽画布上。两套文件名完全一致,因此同一份清单与resources.pri解析逻辑对两个风味都成立。换 Logo 后需重跑脚本,并注意-ReferenceDir必须指向另一套资源目录(脚本会先清空-OutDir)。MSI 向导图banner.bmp/dialog.bmp则由 script-generate-msi-art.ps1 从同一 Logo 生成。
MSI 安装器
构建命令
# 签名 x64 安装器(载荷二进制 + .msi 本身) pwsh __assets/win/script-pack-win-msi.ps1 -Sign # 先装钉死版 wix 工具 + UI 扩展,再打包 pwsh __assets/win/script-pack-win-msi.ps1 -Sign -BootstrapWix # 本地快速迭代:复用 publish 目录、跳过 ICE 校验、用廉价压缩 pwsh __assets/win/script-pack-win-msi.ps1 -SkipPublish -SkipValidation -CompressionLevel mszip输出为__artifacts/bundle/ImageGlass_<version>_win-x64.msi,当前仅 x64(-Platform只接受x64)。VS Code 任务:pack-win-x64-msi(包含在pack-win-all中)。
安装向导与双作用域
向导共四屏:Terms and Privacy(指向官网条款的超链接 + 勾选“I agree”才能进入下一步)、Installation type(按用户/按机器安装,目录默认值随之变化,带 Browse 按钮)、进度、完成(可选“Launch ImageGlass”)。
项目刻意不用WixUI_Advanced:它早于 per-user/per-machine 切换类包,只设置WixAppFolder/ALLUSERS而从不设置MSIINSTALLPERUSER,且其 per-machine 默认会落到 per-user 目录。两个自定义对话框都在 msi/UI.wxs 中。
作用域与提权对照:
| 选择 | 目标目录 | 提权 |
|---|---|---|
| Only me | %LocalAppData%\Programs\ImageGlass | 无 |
| All users | %ProgramFiles%\ImageGlass | 安装开始时弹 UAC |
静默安装示例:
msiexec /i ImageGlass_<version>_win-x64.msi /qn ALLUSERS=2 MSIINSTALLPERUSER=1 # 按用户 msiexec /i ImageGlass_<version>_win-x64.msi /qn ALLUSERS=1 # 按机器 msiexec /i ImageGlass_<version>_win-x64.msi /qn /l*v "%TEMP%\ig.log" # 带日志 msiexec /x {PRODUCT-CODE} /qn # 卸载按机器安装配合/qn时调用方必须已提权,因为静默安装无法弹出 UAC 提示(MSI 日志:MSI_LUA: Installation UI level is silent, no credential elevation is possible)。
为什么对话框必须发布ALLUSERS
这是一个极易踩的坑:对话框必须发布ALLUSERS,仅发布MSIINSTALLPERUSER不够。客户端在启动瞬间就会折叠ALLUSERS=2(日志:MSI (c): Deleting ALLUSERS property...),此时 Property 表里MSIINSTALLPERUSER=1就把上下文定格为按用户,之后清空MSIINSTALLPERUSER是无效操作,只有ALLUSERS=1会被服务端采纳。而命令行两种写法都能生效,因为属性在折叠发生前就已就位。历史教训:10.0.5.825发布时未发布ALLUSERS,导致其“All users”安装实际把文件装进%ProgramFiles%、ARP 行写入 HKLM,却按用户注册产品并把HKMU作用域标记写进 HKCU。
FindRelatedProducts排在该作用域预置之后,原因相同:它会静默跳过与当前生效上下文不同的相关产品(current install is per-user. Related install ... is per-machine. Skipping...),否则旧版本会残留注册。它仍先于LaunchConditions运行,故降级防护不受影响。
可在命令行设置的公共属性:ALLUSERS、MSIINSTALLPERUSER、INSTALLFOLDER、IGDESKTOPSHORTCUT、IGSTARTMENUSHORTCUT、IGREMOVEFILEASSOC、IGAGREETOTERMS。注意IGINSTALLSCOPE只驱动 UI 中的单选按钮,不改变安装上下文。
升级既有安装:作用域锁死与降级防护
Windows Installer 无法在按用户与按机器之间搬移产品——在另一作用域运行主升级时,无法移除它要替换的产品,结果要么回滚、要么装下两份拷贝。因此包从自身HKMU标记所在的注册表根判断当前作用域:
| 签名 | 由谁留下 |
|---|---|
<IgSetupRegKey>\InstallLocation | 所有携带本 authoring 的构建 |
<IgSetupRegKey>\StartMenuShortcut、\DesktopShortcut | 更早的构建(除非用户都拒绝了快捷方式) |
Software\Duong Dieu Phap\{<Ig9UpgradeCode>}\AI_INSTALLPERUSER | ImageGlass 9(Advanced Installer 同样写法) |
<IgSetupRegKey>\InstallLocation还记录精确目录(含自定义路径),升级因此落在旧安装之上而非默认位置。这里不能用ComponentSearch:其Type="directory"要求组件键路径是目录,而 exe 组件的键路径是文件,永远解析不到。
作用域不符时的行为分三种:
- 向导中:作用域被预选且单选组禁用,物理上不可能产生错配;ImageGlass 9 只预选不锁死,因为其移除是尽力而为,强制提权安装反而错误。
- 静默时:错配直接拒绝并提示应使用的命令行,刻意不做自动纠正——安装器在启动时就定格上下文,自定义操作翻转
ALLUSERS只改变是否要求提权,却不会改变已应用到ProgramFiles64Folder的目录重定向,会把按机器安装塞进%LocalAppData%。这是“实测而非臆测”的决策。 - 同版本更旧构建被拒:
ProductVersion第 4 段携带构建号,而 MSI 忽略该段,10.0.5.825与10.0.5.906会被判为相等并落入升级区间,MajorUpgrade自带的降级防护不会触发,旧安装器会顶掉新版。因此安装时在InstallLocation旁记录InstalledBuild,IgBlockOlderBuild拒绝任何更低的构建并复用降级文案;比该记录更早的安装(IGPREVBUILD为空)则不拒绝。 10.0.5.825的“All users”安装被整体拒绝:它实际按用户注册(见上文ALLUSERS问题),没有作用域能升级它。识别特征是 HKLM ARP 行 + HKCU 标记;卸载它即解除封锁。卸载需提权,否则 MSI 无法删除%ProgramFiles%里的文件。- 两种机制都不覆盖早到未留任何标记的安装(用户当时拒绝了两个快捷方式),这种情形仍按老方式失败。
MSI 的工程细节与踩坑记录
- “Launch ImageGlass”动作是 type 50 而非 type 18:
FileRef自定义操作在组件未随会话安装时会报 2753(“The File is not marked for installation”),而 MSI 会跳过键路径已以更高版本存在的组件。它改为从IgLaunchTarget执行,并在ExecuteAction之后才设置为[#FileImageGlassExe]——CostFinalize时对话框选择的目录尚未生效,此时取值还是 per-user 默认路径,启动会静默失败。 Magick.Native-*.dll手工声明为ImageGlass.exe的伴随文件:Costing 在CostFinalize(1000) 进行而RemoveExistingProducts在 1401,MSI 按旧产品的文件决定组件,会跳过键路径已以更高版本存在的组件(Action: Null),随后移除删除该文件,结果两边都没装,只能 Repair 找回。Magick.NET 14.14 给该 DLL 打的版本号是10.2.0.0,14.17.1 却是7.1.2.31,版本倒退了,升级时被静默丢弃。作为伴随文件,其版本读取自只升不降的ImageGlass.exe。任何版本会下降的载荷文件都需要同样处理。- 包绝不能标记为 “UAC compliant”:Word Count 汇总位第 3 位(“不需要提升权限”)会把 MSI 变成 per-user-only 包,MSI 日志
MSIINSTALLPERUSER property is not valid for UAC compliant package,ALLUSERS被删除,按机器选项静默失效而安装仍报成功。WiX 对Scope="perUserOrMachine"正确地保持该位清零,打包器(Assert-DualScopeSummary)也断言它保持清零。提权由解析后的上下文决定,per-user 永不弹窗。 - 版本:
ProductVersion原样使用<IgVersion>全部四段,因此“应用与功能”显示真实构建号。MSI 只比较前三段,故 authoring 设置MajorUpgrade/@AllowSameVersionUpgrades,否则仅第 4 段不同的两个构建会被视为同一产品、永远不触发升级。ProductCode是版本的确定性 UUIDv5(New-DeterministicGuid),已发布构建的msiexec /x {GUID}因此始终可用。可用-ProductVersion覆盖。 - 卸载清理文件类型注册:卸载时先运行
ImageGlass.exe --ig-remove-default-viewer再删文件;传IGREMOVEFILEASSOC=0跳过。主升级期间自动跳过,否则每次更新都会剥掉关联。两个已知缺口:per-machine 卸载时动作以 SYSTEM 身份运行,无法清除交互用户的UserChoice(Explorer 下次选择时自愈);插件新增的扩展名不覆盖。 - 安装会移除 ImageGlass 9(UpgradeCode
{877DB994-AB03-4025-B99D-41CE565E810B},见 Variables.wxi)。移除是尽力而为:per-user 的 v10 无权卸载 per-machine 的 v9,失败不得回滚整个安装。注意 v9 的 per-user 安装用了同一个%LocalAppData%\Programs\ImageGlass目录且把igconfig.json存在里面,那些设置不会保留;v10 读%LocalAppData%\ImageGlass。 - 绝不可移植:
.igportable标记必须永不进入载荷——带标记的已安装副本无法启动(目录不可写,应用报错退出而非回退)。打包器发现标记或_store目录就拒绝构建。 _ext_icons保留(同便携 ZIP):这是非打包安装,应用经典 HKCU/HKLM 注册提供文件图标。- 签名顺序强制:载荷
.exe/.dll必须在 harvest之前签名,因为wix build会记录尺寸与MsiFileHash行并压缩进内嵌 cabinet,之后无法再签。.msi在校验之后最后签名,此后不得再触碰。 - ICE 校验是独立步骤(v5 的
wix build不做任何 ICE 且无开关)。对双作用域包有三个不可避免的抑制:ICE57(快捷方式组件以HKMU键路径携带 per-user 数据,此处唯一正确的根)、ICE61(AllowSameVersionUpgrades)、ICE105(延迟无模拟卸载动作)。打包器用Test-Ice105Invariants手工重断言 ICE105 的其他检查:无 HKLM 注册表行、无服务、无 ODBC 或程序集行、无系统目录。 - 更快的迭代:
-SkipPublish复用__artifacts/publish/win-x64。绝不用于正式发布:版本已编译进二进制。
便携版 ZIP
构建命令
# 按架构签名便携 ZIP(载荷二进制签名;ZIP 本身无法签名) pwsh __assets/win/script-pack-win-zip.ps1 -Platform x64 -Sign pwsh __assets/win/script-pack-win-zip.ps1 -Platform arm64 -Sign # 非便携归档:设置写入 %LocalAppData%\ImageGlass,同 MSIX 构建 pwsh __assets/win/script-pack-win-zip.ps1 -Platform x64 -NoPortableVS Code 任务:pack-win-x64-zip、pack-win-arm64-zip。输出__artifacts/bundle/ImageGlass_<version>_win-<arch>.zip。
便携模式原理
ZIP默认便携:打包器在ImageGlass.exe旁写入一个空.igportable标记文件。应用启动时在自己的目录里寻找该标记(文件名来自Const.PORTABLE_MARKER_FILE=.igportable,见 Const.cs),找到后把写入的一切(igconfig.json、_cache、_logs、_plugins、_lang……)都留在本目录而非%LocalAppData%\ImageGlass。整个文件夹因此可移动、重命名或塞进 U 盘而不丢设置。检测逻辑在 ConfigMode.cs,由BHelper.ConfigPath转换为配置目录。
三条硬约束(均有源码佐证):
- 便携目录必须可写:标记存在但应用无法在该目录建文件(例如解压进了
Program Files),应用报出真实错误并退出,绝不回退到%LocalAppData%——否则会静默地隐藏便携设置于第二个配置之下。ConfigMode.Resolve在检测到标记后用带DeleteOnClose的探针文件实测可写性。 - 标记绝不进入 MSIX:打包 MSIX 的载荷目录只读,带标记的每次启动都会失败。标记只由 ZIP 打包器写入,
__assets/__app里没有它。 - 打包时的护栏:MSI 打包器同样拒绝携带
.igportable或_store的载荷。
打包细节
script-pack-win-zip.ps1的流程与 MSIX 打包器前半段一致:publish → 按归档名建立单层顶层目录(解压不会散落文件到当前目录)→ 剔除*.pdb→ 清理任何残留_store(防-SkipPublish泄漏 Store 许可证到公开归档)→ 写便携标记 → 签名载荷二进制 → 打包。打包用[System.IO.Compression.ZipFile]::CreateFromDirectory而非Compress-Archive:文件量大时快得多,且通配符式Compress-Archive会跳过点前缀的标记文件。includeBaseDirectory:$true保证一切落在归档同名目录下。
Pro 授权与 Store 身份
Store 版的Pro 授权就是包身份本身。Win32AppIdentity.IsMsStorePackage要求运行时包的身份名等于-MsStoreIdentityName,且 publisher id 等于-MsStorePublisher的哈希;Win32StoreEntitlementProvider把该身份当作已购 Pro 的证明。publisher id 是 publisher DN 以 UTF-16LE 编码后 SHA-256 的前 8 字节再做 base32,它是包全名的尾段,最稳妥的重新推导方式是直接读一个已装包的尾段。改动任一参数都会悄悄关掉所有 Store 用户的 Pro——所以改MSSTORE_IDENTITY_NAME/MSSTORE_PUBLISHER_ID(在 Win32AppIdentity.cs)必须与打包参数同 commit。
同一身份还让构建跳过许可证版本作用域检查:LicenseScope.IsScopeExempt(LicenseScope.cs)在IsStoreEntitled时直接豁免,这正是 Store 客户在 Windows 上对未来所有版本都拥有 Pro 的原因,尽管内嵌文件只作用于 major 10。该作用域仍约束 macOS/Linux 上的导出副本。
这一整套只在 Store 条目保持付费应用 + 限时试用时才成立:Windows 在试用期结束后拒绝启动应用,于是“进程在运行”等价于“客户已授权”。若将来列表变为免费或无限试用,就必须替换为实时的 Store 许可证查询。
另一个关联要点是内嵌许可证仅用于导出。msstore 载荷把签名许可证放在ImageGlass\_store\——应用许可证扫描永不查看的子目录,因此它本身不授予任何权限(授权靠 Store 身份);它的存在纯粹是让 Store 客户能导出副本给自己的 macOS/Linux 机器,所以作用域限定在他们购买的主版本线。signed 风味见到_store目录就拒绝构建,-SkipPublish的陈旧复用因此不可能把许可证泄漏进 GitHub 包。任何人仍可解包取出该许可证,这是被接受的设计——泄漏的应对是下一次提交换用全新licenseId。
快速对照:何时用哪条命令
| 场景 | 命令 |
|---|---|
| Store 提交(x64) | pwsh __assets/win/script-pack-win-msix.ps1 -Platform x64 |
| GitHub Release(签名,双架构一个文件) | pwsh __assets/win/script-pack-win-msix.ps1 -Bundle -Sign |
| 传统安装器 | pwsh __assets/win/script-pack-win-msi.ps1 -Sign |
| 免安装便携版 | pwsh __assets/win/script-pack-win-zip.ps1 -Platform x64 -Sign |
| 本地快速迭代 | 各脚本加-SkipPublish(MSI 再加-SkipValidation -CompressionLevel mszip) |
| 一把梭 | VS Code 任务pack-win-all |
所有产物汇入__artifacts/bundle/,供上传 Store 或 GitHub Release。打包脚本本身(script-pack-win-msix.ps1、script-pack-win-msi.ps1、script-pack-win-zip.ps1)包含完整的参数文档与示例,是排查打包问题时的第一手参考。
- 桌面应用
- 图像处理
【免费下载链接】ImageGlass
🏞 A fast, open-source, modern image viewer for 90+ formats – including WEBP, GIF, SVG, AVIF, JXL, HEIC and more – built for smooth browsing across Windows, macOS, and Linux.
相关推荐
Thorium Portable 便携版打包全解:从 .deb 与 mini installer 生成 Linux/Windows zip 便携包的完整流程
Thorium Portable 便携版打包全解:从 .deb 与 mini installer 生成 Linux/Windows zip 便携包的完整流程 本
桌面应用跨平台GeoLibre 便携版 Windows 打包实战:免安装、免管理员权限的 portable zip 方案
GeoLibre 便携版 Windows 打包实战:免安装、免管理员权限的 portable zip 方案 GeoLibre Desktop 除了 NSIS /
数据可视化数据分析桌面应用前端后端Serial Studio Windows 安装完整指南:MSI、便携 ZIP 与 Microsoft Store 三种渠道详解
Serial Studio Windows 安装完整指南:MSI、便携 ZIP 与 Microsoft Store 三种渠道详解 Serial Studio 是
桌面应用数据可视化物联网
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考