title: Windows 插件实现与打包 date: 2026-08-27 tags:
- AiPPT
- Windows
- PowerPoint
- COM
- NSIS
- 打包 status: active
Windows 插件实现与打包
快速打包
WebView前置条件
Publish-Windows.ps1只消费已经同步到Windows仓库的离线页面,不会构建前端或拉取offline.zip。WebView有改动时,先执行WebView实现与打包 > 快速打包,再把ZIP内容同步到:
src/AiPPTAddin/offline/同步时清空旧的Hash文件,并更新offline/0sync.txt。
常用入口:
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass `
-File .\build\Publish-Windows.ps1不传-Sources时显示22个渠道的勾选列表,默认全部选中:
↑/↓ 移动
空格 勾选或取消
A 全选
N 全不选
Enter 确认
Esc 取消指定部分渠道:
.\build\Publish-Windows.ps1 `
-Version 2.0.5.0 `
-Sources PLUGIN,lenovo,soft360默认产物:
artifacts/windows/<version>/AiPPT-Setup-<version>_<source>.exe正式发布:
.\build\Publish-Windows.ps1 `
-Version 2.0.5.0 `
-GitRelease `
-Push `
-Tag v2.0.5.0 `
-NonInteractive发布要求工作区干净、Tag不存在、签名和混淆都启用。全部渠道构建成功后,脚本提交版本文件、创建annotated Tag,并用git push --atomic同时推送分支和Tag。
测试环境缺少签名证书时,可以显式生成未签名包:
.\build\Publish-Windows.ps1 `
-Version 2.0.5.0 `
-Sources PLUGIN `
-SkipSign `
-NonInteractive-SkipReactor会同时跳过混淆。只要跳过签名或混淆,脚本就禁用Git Release和Push。
只检查工具和参数,不构建:
.\build\Publish-Windows.ps1 `
-Version 2.0.5.0 `
-Sources PLUGIN `
-SkipSign `
-SkipReactor `
-PreflightOnly `
-NonInteractive实现概览
Windows端是Add-in Express COM插件。PowerPoint加载COM组件,插件用Office Interop操作PPT,WPF和WebView2负责页面。
PowerPoint
→ Add-in Express COM
→ AddinModule
→ Ribbon/事件
→ WPF或Custom Task Pane
→ WebView2
→ C# WebviewJsCallback
→ Office Interop仓库:
aippt_windows_addin1. 代码分层
PowerPoint入口
src/AiPPTAddin/
├── AddinModule.cs
├── AddinModule.Ribbon.cs
├── AddinModule.RibbonCallbak.cs
├── AddinModule.ContextMenuCallbacks.cs
└── Ribbon.xmlAddinModule负责插件初始化、PowerPoint事件、Ribbon和窗口管理。
Web窗口
src/AiPPTAddin/WebView/
src/AiPPTAddin/TaskPane/两种容器:
| 容器 | 用途 |
|---|---|
| Add-in Express CTP | 停靠在PowerPoint里的侧边栏 |
| WPF BrowserView | 独立浮动窗口 |
两者都使用WebView2加载共享前端页面。
Web和C#通信
Web页面
→ impl/cpp.ts
→ postMessageToClient(module.method)
→ WebView2消息
→ WebviewJsCallback
→ Office InteropC#处理器在:
src/AiPPTAddin/WebviewJsCallback/独立桌面程序
src/AiPPTAddin.App/产物:
AiPPTAddin.App.exe桌面程序能复用Web页面和下载逻辑,但不能代替PowerPoint内的选区、Slide和Shape事件。
2. 开发依赖
| 依赖 | 用途 |
|---|---|
| Windows 11 | 开发和验证系统 |
| Visual Studio | 编译解决方案和MFC插件 |
| MSBuild | Release构建 |
| .NET SDK 8 | 运行Cake Frosting打包项目 |
| Office/PowerPoint | 插件调试 |
| Add-in Express | COM和CTP框架 |
| WebView2 Runtime/SDK | Web页面容器 |
| NSIS | 安装包 |
| .NET Reactor | 混淆DLL和EXE |
| Windows SDK signtool | Authenticode签名 |
| WinRAR | yundong渠道SFX包 |
NSIS还需要项目的MFC UI插件:
NSISUIPlugin/MFCUIPlugin
→ nsMfcPlugin.dll
→ NSIS Plugins/x86-unicode3. 源码构建
构建项目:
src/AiPPTAddin.slnCake入口:
build/src/Build.csproj任务顺序:
Clean
→ Restore
→ SyncConfig
→ MSBuild Release
→ CollectInstallerResources
→ CopyFiles
→ ReactorFiles
→ CompressToZipSyncConfig会改哪些文件
配置来源:
build/build.json主要字段:
{
"ProductVersion": "2.0.5.0",
"InstallerSource": "PLUGIN",
"ProductApiUrl": "https://sop-plugin.aippt.cn/api/"
}构建时会同步到:
src/Directory.Build.props
src/AiPPTSilentInstaller/Program.cs
src/AiPPTAddin/Core/ProductInfos.cs
InstallSuccess/Program.cs
InstallFailed/Program.cs
UninstallSuccess/Program.cs这些改动属于构建输入,不应把最后一个渠道值误提交到主分支。
4. 混淆和程序签名
.NET Reactor
任务:
ReactorFiles处理范围:
AiPPTAddin.*.dll和.exe;adxloader*.dll;- 排除测试程序集;
- 不混淆
AiPPTAddin.Installer.exe; - loader文件不做Reactor保护。
当前保护参数包括:
控制流混淆
调用隐藏
方法虚拟化
防调试
防篡改necrobit和资源加密关闭,没有使用UPX、Themida或VMProtect一类传统PE压缩壳。
正式构建应检查:
dotNET_Reactor.Console.exe存在
许可证已激活
进程退出码为0-SkipReactor只用于本地测试。跳过混淆的产物不应创建正式Tag。
Authenticode
签名封装:
build/common/SignUtils.cs签名对象:
- 混淆后的DLL和EXE;
- InstallSuccess/InstallFailed/UninstallSuccess;
- WebView2Checker;
AiPPTAddin.Installer.exe和CommandLine.dll;adxregistrator.exe和pingo.exe;- uninstall.exe;
- 最终Setup.exe。
正式构建应检查:
signtool.exe存在
证书在CurrentUser或LocalMachine证书库
证书包含私钥
证书未过期
时间戳服务可访问-SkipSign只生成测试包。未签名包不能进入正式发布流程。
5. NSIS安装包
打包项目:
build/setup/Build.csproj模板:
NSISAPPSetup/App-Placeholder.nsi
NSISAPPSetup-soft360/App-Placeholder.nsi
NSISAPPSetup-box/App-Placeholder.nsi模板选择:
| 渠道 | 模板 |
|---|---|
soft360 | NSISAPPSetup-soft360 |
huajun、yundongwin | NSISAPPSetup-box |
| 其他普通渠道 | NSISAPPSetup |
yundong | WinRAR SFX专用流程 |
普通包流程:
复制AiPPT-public到模板App目录
→ 生成安装和卸载文件清单
→ 替换App-Placeholder.nsi占位符
→ 生成App-Build.nsi
→ makensis
→ 生成Setup.exe
→ signtool签名Setup.exe离线WebView如何进入Setup
输入目录:
src/AiPPTAddin/offline/完整链路:
aippt-frontend-addin的dist/offline.zip
→ 人工清空并解压到src/AiPPTAddin/offline
→ 更新0sync.txt
→ AiPPTAddin.csproj以CopyToOutputDirectory复制offline/**
→ MSBuild输出到src/Publish/AiPPT-Release/offline
→ CopyFiles复制到src/Publish/AiPPT-public/offline
→ BuildSetup复制AiPPT-public到NSISAPPSetup*/App
→ 自动生成NSIS File清单
→ Setup.exe安装到$INSTDIR/offline运行时:
$INSTDIR/offline
→ DirectorySync复制到LocalAppData的offline目录
→ WebView2加载offline/<page>.html桌面程序默认加载offline/desktop.html,插件窗口按业务加载offline/<page>.html。启动后还会检查服务端的offline包版本;有更新时下载offline.zip并覆盖LocalAppData中的离线目录。
人工边界只有第一步:前端offline.zip同步到src/AiPPTAddin/offline/。后续MSBuild、Publish、NSIS和安装均由Windows打包链路自动完成。
当前缺失处理:
src/AiPPTAddin/offline/缺失时,MSBuild可能继续执行;- NSIS生成的文件列表或Payload不完整时,makensis失败;
- 运行时页面缺失时记录错误并回退到
offline/page-not-found.html。
COM注册和运行文件
CollectInstallerResources除WebView2Checker外,还收集:
src/AiPPTAddin.Installer/bin/Release/AiPPTAddin.Installer.exe
src/AiPPTAddin.Installer/bin/Release/CommandLine.dll
build/runtime/adxregistrator.exe
build/runtime/files/pingo.exe用途:
| 文件 | 用途 |
|---|---|
AiPPTAddin.Installer.exe | 注册和卸载AiPPT COM Add-in |
CommandLine.dll | Installer命令行参数解析 |
adxregistrator.exe | Add-in Express注册辅助程序 |
pingo.exe | 图片压缩 |
缺少任一文件时,构建直接失败。线上2.0.3.0包与修复后的测试包对比结果为:线上存在而测试包缺少的文件数为0。
6. uninstall.exe流程
三套安装模板分别维护预生成的卸载器:
NSISAPPSetup/uninstall.exe
NSISAPPSetup-soft360/uninstall.exe
NSISAPPSetup-box/uninstall.exe普通包流程:
读取对应模板的uninstall.exe
→ 正式模式下签名并验证Authenticode
→ 复制到App Payload
→ makensis嵌入Setup.exeyundong使用默认目录下的uninstall.exe。
当前约束:
- 修改卸载逻辑后要同步更新三份卸载器;
- 正式模式要求签名验证通过;
-SkipSign只用于测试包;- 缺少卸载器时直接失败,不静默生成不完整安装包。
7. 22个渠道包
当前批量入口:
build/BuildAllSetup/Program.cs渠道:
PLUGIN
mircrosoft
officetools
AiPPT
baoyin
ycj
jzbc
txyyb
qiuye
wepe
soft360
lenovo
ludashi
aikit
soft51ppt
baoySEM
rjjl
txrjgj
hlfh
yundong
huajun
yundongwin大部分渠道的Payload相同,区别是InstallerSource。该值写入注册表,并随安装、启动、卸载和业务请求发送到服务端,用于渠道归因。
渠道例外:
| 渠道 | 差异 |
|---|---|
baoySEM | 无独立SDK,仅InstallerSource=baoySEM归因 |
soft360 | 专用NSIS模板和UI资源 |
lenovo | 保留x86/x64运行时目录 |
yundong | WinRAR SFX、静默安装器和运行时特殊逻辑 |
huajun、yundongwin | box模板和对应UI资源 |
8. yundong SFX
代码:
build/BuildYunDong/依赖:
Rar.exe
SFXConfig.txt
AiPPTSilentInstaller.exe
check_dotnet_and_install.cmd
payload目录流程:
准备payload
→ 签AiPPTSilentInstaller.exe
→ Rar.exe生成SFX
→ 签最终SFX EXEWindows自带ZIP和Compress-Archive不能生成兼容的WinRAR SFX EXE。Windows构建环境可安装:
winget install --id RARLab.WinRAR --exact正式发布还要确认WinRAR授权。
9. 产物检查
每个渠道应有一个文件:
AiPPT-Setup-<version>_<source>.exe检查项:
- 版本和渠道名正确;
- 22个文件没有缺失或重复;
- Setup.exe签名有效;
- 安装后的uninstall.exe签名有效;
- 内部业务EXE和DLL签名有效;
AiPPTAddin.Installer.exe、CommandLine.dll、adxregistrator.exe和files/pingo.exe存在;- Setup Payload包含
offline/desktop.html、offline/settings.html和offline/0sync.txt; soft360、box、yundong能走各自安装流程;- 构建失败时不保留半批产物;
- 跳过签名或混淆时不提交版本、不打Tag。
单渠道烟测通过标准:
安装进程ExitCode=0
注册表LoadBehavior=3
PowerPoint COMAddIns中AiPPTAddin.Release的Connect=true10. 安装后的主要位置
插件安装后会写入PowerPoint加载和AiPPT运行所需文件,并把版本、渠道等设置写入当前用户注册表。
主要注册表项:
HKCU\Software\AiPPT\AiPPT\AiPPTAddin.Client字段:
InstallerSource
version开始菜单目录按安装权限写入All Users或Current User:
Programs/AiPPT/
├── AiPPT插件.lnk
└── 卸载 AiPPT插件.lnk安装前递归清理旧的Programs/AiPPT/目录,再创建新快捷方式,避免升级后残留历史名称或乱码文件。
11. 常见失败
| 错误 | 检查 |
|---|---|
| 找不到MSBuild | Visual Studio工作负载、vswhere、MSBuild路径 |
| 找不到nsMfcPlugin | MFC插件是否编译并复制到NSIS插件目录 |
| Reactor返回101 | .NET Reactor未激活 |
| 找不到签名证书 | USB Key、证书库、私钥和Thumbprint |
| 找不到uninstall.exe | 对应NSIS模板目录是否包含预生成卸载器 |
| COM Add-in显示运行时加载错误 | 检查Installer、CommandLine、adxregistrator、loader位数和注册表 |
| 开始菜单快捷方式乱码 | NSIS模板是否被Windows PowerShell按ANSI读取;模板必须显式按UTF-8读取和写入 |
| 找不到StdUtils.nsh/dll | NSIS Includes和Plugins搜索目录 |
| yundong找不到Rar.exe | WinRAR未安装或路径未配置 |
| 22包数量不对 | BuildAllSetup渠道列表和中途失败日志 |
12. 相关代码
build/build.json
build/src/Program.cs
build/setup/Program.cs
build/BuildAllSetup/Program.cs
build/BuildYunDong/
build/common/SignUtils.cs
NSISAPPSetup*/App-Placeholder.nsi
src/AiPPTAddin/
src/AiPPTAddin.App/
src/webview2-checker/相关文档: