WIX中通过注册表值实现If...Else条件判断的技术问询
在WiX中基于Windows版本做条件判断的正确姿势
首先得指出你当前代码里的关键问题:你用了WiX的预处理器指令<?if?>,但这个指令是编译时执行的,而[WINDOWS_VERSION]是安装时才会从注册表读取的属性——编译的时候这个值根本不存在,所以你的判断不会生效。
下面分两种场景给你解决方案:
场景1:编译时生成不同版本的安装包
如果你的需求是针对不同Windows版本单独编译安装包(比如专门给Win10 Enterprise做一个包),那可以用WiX预处理器变量来实现:
- 先在你的
.wxi文件里定义预处理器变量(或者通过MSBuild参数传递):
<?define TargetWindowsEdition = "Windows10Enterprise"?>
- 然后用
<?if?>做编译时判断:
<?if $(var.TargetWindowsEdition) = "Windows10Enterprise"?> <Directory Id="INSTALLDIR" Name="ETMS"> <Directory Id ="BinDir" Name ="BIN"> <Directory Id ="AssemblyDir" Name ="Assembly"> <Component Id ="BinAssemblyFile" Guid="*"> <!-- 你的组件内容 --> </Component> </Directory> </Directory> </Directory> <?else?> <!-- 其他Windows版本对应的目录结构 --> <Directory Id="INSTALLDIR" Name="ETMSDefault"> <!-- ... --> </Directory> <?endif?>
这种方式需要你针对不同版本编译多次,适合需要单独分发特定版本安装包的场景。
场景2:安装时动态适配不同系统
如果想要一个安装包适配所有系统,在安装时根据当前系统版本动态调整行为,那得用Windows Installer的原生条件机制,结合注册表读取或预定义属性:
第一步:正确读取系统版本信息
优先推荐用Windows Installer预定义的VersionNT属性(它是系统版本的数值表示,比读注册表ProductName更可靠),如果需要区分企业版/专业版这类版本类型,再读注册表的ProductName:
<!-- 读取系统版本类型(比如Windows 10 Enterprise) --> <Property Id="WINDOWS_EDITION"> <RegistrySearch Id='WinEditionSearch' Type='raw' Root='HKLM' Key='SOFTWARE\Microsoft\Windows NT\CurrentVersion' Name='ProductName' Win64="yes" <!-- 64位系统必须加这个,避免注册表重定向 --> /> </Property> <!-- 也可以读取系统版本号(比如10.0),结合预定义的VersionNT更准确 --> <Property Id="WINDOWS_VERSION"> <RegistrySearch Id='WinVersionSearch' Type='raw' Root='HKLM' Key='SOFTWARE\Microsoft\Windows NT\CurrentVersion' Name='CurrentVersion' Win64="yes" /> </Property>
第二步:用Condition控制组件/功能安装
比如只在Win10 Enterprise上安装某个组件:
<Feature Id="MainFeature" Title="核心功能" Level="1"> <!-- 只有当系统是Win10 Enterprise时才安装这个组件 --> <ComponentRef Id="BinAssemblyFile" Condition="[WINDOWS_EDITION] = "Windows 10 Enterprise"" /> <!-- 其他组件默认安装 --> <ComponentRef Id="CommonFiles" /> </Feature>
第三步:动态设置安装目录(如果需要)
如果要根据系统版本设置不同的安装目录,得用自定义动作在CostInitialize之前修改INSTALLDIR属性:
<!-- 定义自定义动作,设置不同的安装路径 --> <CustomAction Id="SetDirForWin10Ent" Property="INSTALLDIR" Value="[ProgramFilesFolder]\ETMS\BIN\Assembly" Execute="firstSequence" /> <CustomAction Id="SetDirForOthers" Property="INSTALLDIR" Value="[ProgramFilesFolder]\ETMS\Default" Execute="firstSequence" /> <!-- 在安装序列里执行自定义动作 --> <InstallExecuteSequence> <Custom Action="SetDirForWin10Ent" Before="CostInitialize" > WINDOWS_EDITION = "Windows 10 Enterprise" </Custom> <Custom Action="SetDirForOthers" Before="CostInitialize" > NOT WINDOWS_EDITION = "Windows 10 Enterprise" </Custom> </InstallExecuteSequence>
重要提醒
- 注册表的
ProductName会随系统本地化和版本更新变化(比如Win10 Enterprise LTSC的名称可能不同),如果只是判断系统版本号,用Windows Installer预定义的VersionNT、VersionNTBuild属性更可靠。 - 64位系统上一定要给RegistrySearch加上
Win64="yes",否则会读到Wow6432Node下的32位注册表项,导致信息不准确。
内容的提问来源于stack exchange,提问作者Kai Sek
相关产品推荐
相关产品推荐

