Installation 如何使用WiX将多个条目添加到`PATH`Envirnoment变量?

Installation 如何使用WiX将多个条目添加到`PATH`Envirnoment变量?,installation,wix,windows-installer,Installation,Wix,Windows Installer,我正在创建一个MSI安装程序,需要向PATH环境变量添加多个条目。根据: 每行只能包含一个值。例如,条目值;价值[~]是多个值,不应使用,因为它会导致不可预测的结果。输入值;[~]只是一个值 我的安装程序源代码目前看起来像这样(注意,这是每台机器的安装),这违反了上述文档: <!-- NOTE: These two features are mutually exclusive --> <Feature Id="Feature1" Level="1000" Absent="al

我正在创建一个MSI安装程序,需要向
PATH
环境变量添加多个条目。根据:

每行只能包含一个值。例如,条目
值;价值[~]
是多个值,不应使用,因为它会导致不可预测的结果。输入<代码>值;[~]只是一个值

我的安装程序源代码目前看起来像这样(注意,这是每台机器的安装),这违反了上述文档:

<!-- NOTE: These two features are mutually exclusive -->
<Feature Id="Feature1" Level="1000" Absent="allow" AllowAdvertise="no" InstallDefault="local" TypicalDefault="install">
    <Component Directory="INSTALLFOLDER">
        <RegistryValue Action="write" Type="int" Root="HKLM" Key="SOFTWARE\MyProduct" Name="MyPathEntry1" Value="1" KeyPath="yes" />
        <Environment Id="AddPathEntry1" Name="PATH" Value="[INSTALLFOLDER]SubDir1" Action="set" Permanent="yes" Part="last" System="yes" />
    </Component>
</Feature>

<Feature Id="Feature2" Level="1000" Absent="allow" AllowAdvertise="no" InstallDefault="local" TypicalDefault="install">
    <Component Directory="INSTALLFOLDER">
        <RegistryValue Action="write" Type="int" Root="HKLM" Key="SOFTWARE\MyProduct" Name="MyPathEntry2" Value="1" KeyPath="yes" />
        <Environment Id="AddPathEntry2" Name="PATH" Value="[INSTALLFOLDER]SubDir1;[INSTALLFOLDER]SubDir2;[INSTALLFOLDER]SubDir3" Action="set" Permanent="yes" Part="last" System="yes" />
    </Component>
</Feature>

现在,根据MSDN文档,尽管上述“技术上”是一种违规行为,但似乎有效。我已经测试了新安装、修改安装和升级。一切似乎都很顺利。但我从MSI中学到的一件事是,只要有可能,最好遵守规则,避免弄乱人们的机器

添加仅包含单个路径组件的独立(即非互斥)功能的自然解决方案不起作用,因为对于MSI,您无法保证功能和/或组件的安装顺序。但是,在这种情况下,路径组件添加到
path
环境变量的顺序很重要,因为在查找不合格的可执行文件时如何使用
path
变量

另一个可能浮现在脑海中的问题是,我为什么要使用功能?我想让产品的安装人员可以选择在以后通过标准的“添加/删除程序”或“程序和功能”控制面板小程序更改安装选项


那么,如何在遵循MSDN推荐的指南的同时,以确定的顺序将多个路径条目添加到
path
环境变量中?或者MSDN的指导已经过时,而我目前所做的一切都很好吗?

我找到了一种方法来做到这一点,它不会违反MSDN针对我特定情况的指导

确切的情况是,我有一个主程序可执行文件,安装程序可能希望也可能不希望能够从Windows命令Shell运行。此外,安装程序可能希望也可能不希望从Windows命令行程序运行其他实用程序

最初的建模方式是使用单选按钮决定如何更新系统
路径
环境变量,由3个相互排斥的功能组成。这3个特点归结为:

  • 不要修改系统的
    路径
    环境变量(即,程序和可选工具不能通过在任何目录位置键入可执行文件的名称从Windows命令外壳运行)
  • 更新系统的
    PATH
    环境变量,以便只有主可执行文件可以在任何给定路径下从Windows命令行程序运行
  • 更新系统的
    路径
    环境变量,以同时添加其他实用工具路径
  • 我意识到这里实际上只有两个特性,它们甚至不是相互排斥的,但是一个依赖于另一个。上面列出的第一个单选按钮并不是真正的功能——它是一个禁止操作的按钮;它没有安装任何东西!第二个单选按钮代表“主要”功能,主要可执行文件的目录被添加到系统的
    路径中。第三个单选按钮取决于第二个:如果将主可执行文件添加到
    路径
    ,则还可以将其他实用程序添加到
    路径

    这将导致更简单的UI。使用复选框代替单选按钮,第二个复选框将被禁用,除非选中第一个复选框。这也使得实现更加简单,以确保所选功能的组合(例如,对于命令行安装)是有效的

    简而言之,在我的特殊情况下,wixxml将归结为以下内容。我确信这可以被推广(或修改)以适应其他类似的场景

    <Feature Id="AddExeToPath" Level="1" Absent="allow" AllowAdvertise="no" InstallDefault="local" TypicalDefault="install">
      <Component Id="ExePath" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
        <CreateFolder />
        <Environment Id="ExePath" Name="MY_PATHS" Value="[INSTALLFOLDER]SubDir1" Action="set" Part="first" System="yes" />
      </Component>
      <Component Directory="INSTALLFOLDER">
        <RegistryValue Action="write" Type="integer" Root="HKLM" Key="SOFTWARE\MyProduct" Name="AddExeToPath" Value="1" KeyPath="yes" />
        <Environment Id="AddToPath" Name="PATH" Value="%MY_PATHS%" Action="set" Part="last" System="yes" /> 
      </Component>
      <Component Id="RemoveExeFromPathOnUninstall" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
        <Condition>REMOVE><AddExeToPath OR REMOVE="ALL"</Condition>
        <Environment Id="RemoveFromPath" Name="PATH" Value="%MY_PATHS%" Action="remove" />
      </Component>
    </Feature>
    
    <Feature Id="AddToolsToPath" Level="1000" Absent="allow" AllowAdvertise="no" InstallDefaut="local" TypicalDefault="install">
      <Component Id="SubDir2" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
        <CreateFolder />
        <Environment Id="SubDir2" Name="MY_TOOLS" Value="[INSTALLFOLDER]SubDir2" Action="set" Part="first" System="yes" />
      </Component>
      <Component Id="SubDir3" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
        <CreateFolder />
        <Environment Id="SubDir3" Name="MY_TOOLS" Value="[INSTALLFOLDER]SubDir3" Action="set" Part="last" System="yes" />
      </Component>
      <Component Directory="INSTALLFOLDER">
        <RegistryValue Action="write" Type="integer" Root="HKLM" Key="SOFTWARE\MyProduct" Name="AddToolsToPath" Value="1" KeyPath="yes" />
        <Environment Id="AddToolsToPath" Name="MY_PATHS" Value="%MY_TOOLS%" Action="set" Part="last" System="yes" />
      </Component>
    </Feature>
    
    <CustomAction Id="InvalidPathFeatureSelection" Error="25000" Execute="firstSequence" />
    
    <InstallExecuteSequence>
      <Custom Action="InvalidPathFeatureSelection" Before="InstallValidate">
        <![CDATA[NOT (REMOVE="ALL" OR (&AddToolsToPath >= 3 IMP &AddExeToPath >= 3))]]>
      </Custom>
    </InstallExecuteSequence>
    
    
    删除>=3))]>
    
    这组功能和组件产生以下结果:

  • 如果选择功能AddExeToPath进行安装,则该功能的以下组件将导致:

  • 将创建名为
    MY_PATHS
    的环境变量,该变量包含主可执行文件的路径
  • 更新环境变量
    PATH
    ,将
    %MY\u PATHS%
    置于其当前值的末尾
  • 如果选择功能AddToolStopPath,将安装3个组件:

  • 创建/设置环境变量
    MY_TOOLS
    ,并将
    [INSTALLFOLDER]SubDir2
    放置在变量现有值(如果有)的前面
  • 创建/设置环境变量
    MY_TOOLS
    ,并将
    [INSTALLFOLDER]子项3
    放置在变量现有值(如果有)的末尾
  • 注意
    这两个组件的定义方式确保了添加到
    MY_TOOLS
    的路径以适当的顺序添加

  • 更新环境变量
    MY\u path
    ,将
    %MY\u TOOLS%
    放置在现有变量的末尾;同样,这保留了路径的正确顺序
  • 因此,你最终得到的是:

    • MY_TOOLS
      =
      [INSTALLFOLDER]子菜单2;[INSTALLFOLDER]子目录3
    • MY_路径
      =
      [INSTALLFOLDER]SubDir1;%我的工具%
    • 路径
    =
    ;%我的路径%

    我找到了一种方法来做到这一点,它不会违反MSDN针对我特定情况的指导

    确切的情况是,我有一个主程序可执行文件,安装程序可能会,也可能不会