从 Rust 自定义操作内部读取时,Wix CustomActionData 属性值 10 次中有 2 次为空

问题描述 投票:0回答:1

在 WIX 代码中,我们声明了延迟的自定义操作,该操作将保护凭证和 辅助自定义操作,为其设置 CustomActionData 值,如下所示:

    <CustomAction Id="SetUserNamePasswordForDefferedAction" Property="HandleAccountInfoCustomAction" Value="[ACCOUNT_USERNAME],[ACCOUNT_PASSWORD],[INSTALLLOCATION],[SERVICEACCOUNT]" HideTarget="no" Return="check" />
    <CustomAction Id="HandleAccountInfoCustomAction" DllEntry="handle_account_info" BinaryKey="service_account_dll" Execute="deferred" HideTarget="no" Impersonate="no" Return="check"/>
    <Binary Id="service_account_dll" SourceFile="service_account.dll" />

    <InstallExecuteSequence>
        <Custom Action="HandleAccountInfoCustomAction" Before="InstallFinalize">NOT Installed</Custom>
        <Custom Action="SetUserNamePasswordForDefferedAction" Before="HandleAccountInfoCustomAction">NOT Installed</Custom>
    </InstallExecuteSequence>

service_account_dll
在 Rust 中实现,但以 C 格式导出入口点
handle_account_info
。读取自定义操作数据的 Rust 代码如下:

unsafe fn retrieve_property_from_msi_db(
    h_install: MSIHANDLE,
    property_name_str: &str,
) -> StdResult<String, u32> {
    let property_name = get_ptr_to_cstring(property_name_str);
    custom_action_log(&format!("Retrieve {property_name_str} from MSI db"));
    let mut msi_get_property_call_count = 0usize;
    let mut res;
    let mut req_status;
    let mut buff = [0u8; BUFFER_SIZE];

    res = 0u32;
    req_status = 234u32; // ERROR_MORE_DATA

    while (WIN32_ERROR(req_status) == ERROR_MORE_DATA || res == 0) && msi_get_property_call_count < 5 {
        res = buff.len() as u32;
        req_status = MsiGetPropertyA(
            h_install,
            PCSTR::from_raw(property_name),
            PSTR::from_raw(buff.as_mut_ptr()),
            Some(&mut res as *mut u32),
        );
        if msi_get_property_call_count > 0 && WIN32_ERROR(req_status) == ERROR_MORE_DATA {
            // Register the occurrence of a known race condition in MSI
            custom_action_log(format!("WARN: Multiple calls to MsiGetPropertyA ({msi_get_property_call_count}) returned ERROR_MORE_DATA.").as_str());
        }
        if res == 0 {
            custom_action_log(format!("WARN: MsiGetPropertyA returned 0 bytes for property {property_name_str}.").as_str());
            std::thread::sleep(Duration::from_millis(10));
        }

        msi_get_property_call_count += 1;

        if res as usize > BUFFER_SIZE {
            custom_action_log(format!("Custom action buffer size is too small: Needed {res}/available {BUFFER_SIZE}.").as_str());
            return Err(ERROR_INSTALL_FAILED.0);
        }
    }
    if ERROR_SUCCESS != WIN32_ERROR(req_status) {
        custom_action_log(format!("Failed to retrieve user name from MSI:WIN_32ERROR {:?}, req_status: {req_status}", WIN32_ERROR(req_status)).as_str());
        return Err(ERROR_INSTALL_FAILED.0);
    }

    let property = std::str::from_utf8_unchecked(&buff[..res as usize]);

    Ok(property.to_string())
}

十分之二或三我在自定义操作日志中收到以下内容:

2023-11-14 13:29:47 - Retrieve CustomActionData from MSI db
2023-11-14 13:29:47 - WARN: MsiGetPropertyA returned 0 bytes for property CustomActionData.
2023-11-14 13:29:47 - WARN: MsiGetPropertyA returned 0 bytes for property CustomActionData.
2023-11-14 13:29:47 - WARN: MsiGetPropertyA returned 0 bytes for property CustomActionData.
2023-11-14 13:29:47 - WARN: MsiGetPropertyA returned 0 bytes for property CustomActionData.
2023-11-14 13:29:47 - WARN: MsiGetPropertyA returned 0 bytes for property CustomActionData.
2023-11-14 13:29:47 - service_account CustomActionData data retrieved from MSI db.
2023-11-14 13:29:47 - TROUBLESHOOTING: CustomActionData:
2023-11-14 13:29:47 - CustomActionData property is not in the expected format

成功运行会产生以下日志:

2023-11-14 13:28:48 - Retrieve CustomActionData from MSI db
2023-11-14 13:28:48 - service_account CustomActionData data retrieved from MSI db.
2023-11-14 13:28:48 - TROUBLESHOOTING: CustomActionData: ,,C:\MyApp,NT Authority\Local Service

请帮忙:-)

wix windows-installer race-condition intermittent
1个回答
0
投票

我通过改变策略解决了自己的问题。长话短说,自定义操作现在是一个独立的可执行文件,其中参数通过命令行传递,而不是在 DLL 中实现并由 wix 安装程序应用程序加载的自定义操作。 Wix 支持在不记录命令行参数的情况下执行此操作,因此不会记录密码。基本上,我遵循了这篇文档文章,特别是WixSilentExec风格。

我对为什么从 Wix 直接访问 dll 变得不稳定的理解是,通过 MSI 数据库中的 CustomActionData 属性传递参数值的机制很容易出现竞争条件。

© www.soinside.com 2019 - 2024. All rights reserved.