自定义操作中设置REG_MULTI_SZ类型MSI属性的API及技巧咨询
解决MSI属性设置REG_MULTI_SZ类型字符串的问题
嘿,这个问题我之前做Windows Installer自定义操作时也踩过坑!确实,MsiSetProperty会把第一个\0当作字符串的结束符,直接传入REG_MULTI_SZ格式的字节流肯定不行——毕竟MSI属性本质上是不支持内嵌空字符的字符串类型,这是它的设计限制。
不过有几个靠谱的技巧可以实现你的需求,分两种场景来说:
场景1:用WiX等打包工具直接写入注册表
如果你是用WiX这类主流打包工具,根本不需要写自定义操作折腾!WiX的RegistryValue元素原生支持multiString类型,你只需要用分号;分隔多个字符串作为Value值,WiX会自动帮你转换成REG_MULTI_SZ格式写入注册表:
<RegistryValue Root="HKLM" Key="Software\YourApp\Settings" Name="MultiValueList" Type="multiString" Value="FirstItem;SecondItem;ThirdItem" />
场景2:必须通过自定义操作设置属性再处理
如果你的业务逻辑必须先把多字符串存入MSI属性,之后再写入注册表,那可以这么做:
步骤1:用分号分隔多字符串,存入MSI属性
在自定义操作中,把REG_MULTI_SZ的所有子字符串用分号连接成一个单一字符串,再调用MsiSetProperty设置到目标属性:
// 示例:把三个字符串用分号连接 std::wstring multiValue = L"Item1;Item2;Item3"; MsiSetProperty(hInstall, L"MULTI_STRING_PROPERTY", multiValue.c_str());
步骤2:读取属性并转换为REG_MULTI_SZ格式写入注册表
当需要把这个属性写入注册表时,再写一个自定义操作:
- 调用
MsiGetProperty读取分号分隔的字符串 - 把分号替换为
\0,最后再追加两个\0(REG_MULTI_SZ要求以双空字符结尾) - 用
RegSetValueEx写入注册表,指定类型为REG_MULTI_SZ
示例代码片段(C++):
WCHAR propValue[1024] = {0}; DWORD propSize = ARRAYSIZE(propValue); MsiGetProperty(hInstall, L"MULTI_STRING_PROPERTY", propValue, &propSize); // 转换分号分隔为\0分隔,准备REG_MULTI_SZ缓冲区 std::vector<WCHAR> multiSzBuffer; for (WCHAR c : propValue) { if (c == L';') { multiSzBuffer.push_back(L'\0'); } else { multiSzBuffer.push_back(c); } } // 追加双空字符结尾 multiSzBuffer.push_back(L'\0'); multiSzBuffer.push_back(L'\0'); // 写入注册表 HKEY hKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\YourApp\\Settings", 0, KEY_WRITE, &hKey) == ERROR_SUCCESS) { RegSetValueEx(hKey, L"MultiValueList", 0, REG_MULTI_SZ, (BYTE*)multiSzBuffer.data(), multiSzBuffer.size() * sizeof(WCHAR)); RegCloseKey(hKey); }
注意事项
- 如果你的子字符串本身包含分号,需要先转义(比如用
\;),在读取转换时再还原,避免拆分错误 - 不要尝试直接把带
\0的字符串传入MsiSetProperty,MSI会直接截断到第一个空字符,这是无法绕过的设计限制
内容的提问来源于stack exchange,提问作者user3664223
相关产品推荐
相关产品推荐

