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

时间:2017-03-05 21:34:00

标签: installation wix windows-installer

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

  

每行只能包含一个值。例如,条目Value;Value;[~]不止一个值,因此不会使用,因为它会导致不可预测的结果。条目Value;[~]只是一个值。

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

<!-- 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的指导是否过时,我目前正在做的事情是完全正常的?

1 个答案:

答案 0 :(得分:0)

我想办法做到这一点,不违反MSDN对我特定情况的指导。

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

最初建模的方式是使用单选按钮决定如何更新系统PATH环境变量的一组3个互斥功能。 3个功能归结为:

  1. 不要修改系统的PATH环境变量(即只能在任何目录位置键入可执行文件的名称,无法从Windows命令行管理程序运行程序和可选工具。)
  2. 更新系统的PATH环境变量,以便只能在任何给定路径上从Windows命令行管理程序运行主可执行文件。
  3. 更新系统的PATH环境变量以添加其他实用程序工具路径。
  4. 我意识到这里实际上只有两个特征,它们甚至不是相互排斥的,而是一个依赖于另一个。上面列出的第一个单选按钮实际上不是一个功能 - 它是一个无操作;它没有安装任何东西!第二个单选按钮表示“主要”功能,因为主要可执行文件的目录已添加到系统的PATH中。第三个单选按钮取决于第二个:如果主要可执行文件已添加到PATH,那么您还可以向PATH添加其他实用程序。

    这会产生更简单的用户界面。使用复选框代替单选按钮,除非选中第一个复选框,否则将禁用第二个复选框。这也导致更简单的实现,以确保所选功能的组合(例如,对于命令行安装)有效。

    简而言之,这就是WiX XML在我的特定情况下可以归结为什么。我确信这可以推广(或修改)以适应其他类似场景。

    <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>
    

    这组功能和组件产生以下结果:

    1. 如果选择要安装的功能 AddExeToPath ,则会导致该功能的以下组件出现:

      1. 创建名为MY_PATHS的环境变量,其中包含主可执行文件的路径。
      2. 更新了环境变量PATH,将%MY_PATHS%放在最后的当前值。
    2. 如果选择了 AddToolsToPath 功能,则会安装3个组件:

      1. 创建/设置环境变量MY_TOOLS,并将[INSTALLFOLDER]SubDir2放在前面 变量的现有值(如果有)
      2. 创建/设置环境变量MY_TOOLS,并将[INSTALLFOLDER]SubDir3放在结束 变量的现有值(如果有)中。
      3.   

        注意
          这两个组件定义了它们确保添加到MY_TOOLS的路径以适当顺序添加的方式。

        1. 环境变量MY_PATHS已更新,%MY_TOOLS%位于现有变量的 结束 ;再次,这保留了正确的路径排序。

        所以你最终得到的是:

        • MY_TOOLS = [INSTALLFOLDER]SubDir2;[INSTALLFOLDER]SubDir3
        • MY_PATHS = [INSTALLFOLDER]SubDir1;%MY_TOOLS%
        • PATH = <existing_PATH_value>;%MY_PATHS%