如何从延迟执行的C++ DLL自定义操作中设置WiX属性
答案:可以实现,但需要通过间接方式
延迟执行的自定义操作(Execute="deferred")由于运行在系统上下文,并且和安装序列的常规会话上下文隔离开,所以无法直接修改WiX的常规属性并让后续安装步骤读取到这些更新后的值。不过我们可以通过「临时公共属性 + 立即执行自定义操作」的组合来实现数据回传,具体方案如下:
核心思路
- 在延迟CA中,将更新后的属性值写入一个公共临时属性(全大写命名,确保跨上下文可见)。
- 安排一个立即执行的自定义操作在延迟CA之后运行,负责读取这个临时属性的值,并将其赋值给目标属性(比如你需要更新的
THREE)。
具体实现步骤
1. WiX配置修改
首先在WiX项目中添加临时公共属性,并调整自定义操作的执行顺序:
<!-- 定义公共临时属性,用于传递更新后的值(必须全大写,Secure="yes"确保跨上下文访问) --> <Property Id="UPDATED_THREE" Secure="yes" /> <!-- 原有的CustomActionData设置CA --> <CustomAction Id="SetOutputProperty" Property="custActID" Value="ONE=[ONE];TWO=[TWO];THREE=[THREE];" /> <!-- 原有的延迟执行CA --> <CustomAction Id="custActID" BinaryKey="BIN_MY_DLL" DllEntry="dllEntryFunction" Impersonate="no" Execute="deferred" Return="check" HideTarget='yes' /> <!-- 新增:立即执行CA,用于将临时属性的值同步到THREE --> <CustomAction Id="SyncThreeProperty" BinaryKey="BIN_MY_DLL" DllEntry="syncThreeProperty" Impersonate="no" Execute="immediate" Return="check" /> <!-- 调整安装序列顺序:先设置CustomActionData → 执行延迟CA → 同步属性 --> <InstallExecuteSequence> <Custom Action="SetOutputProperty" Before="custActID" /> <Custom Action="custActID" After="InstallFiles" /> <Custom Action="SyncThreeProperty" After="custActID" /> </InstallExecuteSequence>
2. C++ DLL代码实现
在你的C++ DLL中,需要实现两个函数:延迟CA的入口函数(处理业务逻辑并设置临时属性),以及立即CA的入口函数(同步属性值)。
延迟CA入口函数(dllEntryFunction)
#include <windows.h> #include <msi.h> #include <msiquery.h> #include <tchar.h> UINT __stdcall dllEntryFunction(MSIHANDLE hInstall) { UINT result = ERROR_SUCCESS; TCHAR customActionData[1024] = {0}; TCHAR originalThree[256] = {0}; TCHAR updatedThree[256] = {0}; // 读取CustomActionData中的原始THREE值 if (MsiGetProperty(hInstall, TEXT("CustomActionData"), customActionData, nullptr) == ERROR_SUCCESS) { // 解析CustomActionData,提取THREE字段 LPTSTR threePtr = _tcsstr(customActionData, TEXT("THREE=")); if (threePtr != nullptr) { threePtr += 6; // 跳过"THREE="前缀 LPTSTR endPtr = _tcsstr(threePtr, TEXT(";")); if (endPtr != nullptr) { _tcsncpy(originalThree, threePtr, endPtr - threePtr); } else { _tcscpy(originalThree, threePtr); } } } // 模拟业务逻辑:验证并更新THREE的值 _stprintf_s(updatedThree, TEXT("%s_verified"), originalThree); // 将更新后的值写入临时公共属性 result = MsiSetProperty(hInstall, TEXT("UPDATED_THREE"), updatedThree); if (result != ERROR_SUCCESS) { return result; } return ERROR_SUCCESS; }
立即CA入口函数(syncThreeProperty)
UINT __stdcall syncThreeProperty(MSIHANDLE hInstall) { UINT result = ERROR_SUCCESS; TCHAR updatedThree[256] = {0}; // 读取临时属性UPDATED_THREE的值 result = MsiGetProperty(hInstall, TEXT("UPDATED_THREE"), updatedThree, nullptr); if (result != ERROR_SUCCESS) { return result; } // 将更新后的值赋值给目标属性THREE result = MsiSetProperty(hInstall, TEXT("THREE"), updatedThree); if (result != ERROR_SUCCESS) { return result; } return ERROR_SUCCESS; }
关键注意事项
- 公共属性规则:用于跨上下文传递的属性必须是全大写命名,并且设置
Secure="yes",否则系统上下文的延迟CA设置的值无法被用户上下文的立即CA读取。 - Impersonate设置:延迟CA必须设置
Impersonate="no"(运行在系统上下文),同步用的立即CA建议也设置Impersonate="no",避免权限问题导致无法读取属性。 - 执行顺序:必须严格按照「设置CustomActionData → 执行延迟CA → 同步属性」的顺序安排,否则会出现数据读取不到的情况。
- 回滚处理(可选):如果需要在安装回滚时恢复
THREE的原始值,你还需要添加对应的回滚自定义操作,将原始值存储在另一个临时属性中,回滚时恢复。
内容的提问来源于stack exchange,提问作者pi.314
相关产品推荐
相关产品推荐

