You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从延迟执行的C++ DLL自定义操作中设置WiX属性

答案:可以实现,但需要通过间接方式

延迟执行的自定义操作(Execute="deferred")由于运行在系统上下文,并且和安装序列的常规会话上下文隔离开,所以无法直接修改WiX的常规属性并让后续安装步骤读取到这些更新后的值。不过我们可以通过「临时公共属性 + 立即执行自定义操作」的组合来实现数据回传,具体方案如下:

核心思路

  1. 在延迟CA中,将更新后的属性值写入一个公共临时属性(全大写命名,确保跨上下文可见)。
  2. 安排一个立即执行的自定义操作在延迟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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:35:21