如何在Wix3构建的MSI安装程序中关联自定义动作与进度条?
解决Wix 3中C++自定义动作关联进度条的问题
我之前也踩过Wix 3里C++自定义动作进度条不更新的坑,折腾了好一阵才理顺,给你分享下关键步骤和避坑点:
1. 确认自定义动作的执行类型
只有**延迟执行(Deferred)**的自定义动作才能在安装过程中更新进度条——即时(Immediate)动作是在序列早期执行的,这时候进度条还没进入激活状态,发送的进度消息根本不会被处理。
在Wix的XML里定义自定义动作时,一定要加上Execute="deferred"和Impersonate="no"(延迟动作通常需要系统权限):
<CustomAction Id="MyCppCustomAction" BinaryKey="MyCppBinary" DllEntry="MyCustomActionFunc" Execute="deferred" Impersonate="no" />
同时要把它放在InstallExecuteSequence的正确位置:在InstallInitialize之后,InstallFinalize之前:
<InstallExecuteSequence> <Custom Action="MyCppCustomAction" After="InstallInitialize">NOT Installed</Custom> </InstallExecuteSequence>
2. 正确调用WcaProgressMessage
首先要确保你的自定义动作代码里初始化了WCA框架——开头调用WcaInitialize,结尾调用WcaFinalize,否则WcaProgressMessage会失效:
UINT __stdcall MyCustomActionFunc(MSIHANDLE hInstall) { UINT uiRetVal = ERROR_SUCCESS; HRESULT hr = S_OK; // 初始化WCA hr = WcaInitialize(hInstall, "MyCustomActionFunc"); ExitOnFailure(hr, "Failed to initialize WCA"); // --- 你的任务逻辑开始 --- UINT totalSteps = 10; // 根据实际任务拆分步骤数 for (UINT i = 0; i < totalSteps; i++) { // 执行单个任务步骤 DoYourTask(i); // 计算当前绝对进度百分比 DWORD progress = (i + 1) * 100 / totalSteps; // 发送进度更新消息 // 参数:消息类型(MESSAGE_ACTIONDATA)、是否增量更新(FALSE=绝对进度)、进度值 hr = WcaProgressMessage(MESSAGE_ACTIONDATA, FALSE, progress); if (FAILED(hr)) { WcaLog(LOGMSG_ERROR, "Failed to send progress message: 0x%x", hr); goto LExit; } } // --- 你的任务逻辑结束 --- LExit: uiRetVal = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; WcaFinalize(uiRetVal); return uiRetVal; }
这里要注意:
- 如果你的任务是增量式的(比如每次完成固定比例的工作),可以把第二个参数设为
TRUE,第三个参数传增量值(比如每次加10)。 - 一定要用
WcaLog记录错误,方便后续排查。
3. 配置进度文本
给自定义动作添加ProgressText,这样安装程序会在进度条上方显示当前动作的描述,同时也能确保进度系统正确关联这个动作:
<ProgressText Action="MyCppCustomAction">正在执行自定义任务,请稍候...</ProgressText>
4. 常见排查要点
- 检查安装日志:用
msiexec /i YourInstaller.msi /l*v install.log生成详细日志,搜索WcaProgressMessage看有没有错误返回码,或者进度消息是否被正确发送。 - 确认自定义动作没有被跳过:检查序列里的条件(比如
NOT Installed只在首次安装执行,如果是升级/修复要调整条件)。 - 不要在即时动作里尝试更新进度:即时动作阶段进度条还没开始运转,所有进度消息都会被忽略。
内容的提问来源于stack exchange,提问作者Victor Hugo
相关产品推荐
相关产品推荐

