使用wix安装程序根据条件复制外部文件

时间:2014-09-24 09:20:27

标签: wix windows-installer wix3.7

我的wix对话框上有几个单选按钮。当我选择第一个时,我直接通过对话框输入信息,但是当选择第二个选项时,用户必须选择配置文件在网络上的位置,所以我想将此文件复制到目标位置,但仅限于第二个选项已选择单选按钮,用户已选择该文件。

所以这个问题应该分为三部分:

1)如何将外部文件从网络复制到目标位置

2)仅当第二个单选按钮和文件都已设置时,如何复制此文件。

3)如果不可行,还有其他建议吗?

请注意,我的单选按钮选择存储在名为CONFIGURATIONSELECTION的变量中,所选文件存储在名为FILEPATH的变量中。

我认为以下内容可行但

  <Component Id="CMP_Startup.Config" Guid="0C301558-1894-4A7C-A0A4-C47660F9D334">
    <Condition>
      <![CDATA[(CONFIGURATIONSELECTION = 2 AND FILEPATH <> "")]]>
    </Condition>
    <File Id="FILE_Startup.Config" Source="FILEPATH" Compressed="no" />
  </Component>

但它在编译时抛出错误,即"The system cannot find the FILEPATH"

我甚至可以这样做吗?如果没有,我应该使用CustomAction手动复制文件吗?如果是这样,我怎么能在安装的最后一步做到这一点?

感谢。

2 个答案:

答案 0 :(得分:2)

我最终使用了CustomAction方法。希望这有助于其他人

请记住:
   - 我使用单选按钮,选择存储在CONFIGURATIONSELECTION变量中    - 我使用自定义操作,允许用户通过文件选择对话框选择文件,并将返回的结果存储在FILEPATH变量中。

首先,注意变量定义:

<Product>
    ...
    <Property Id="CONFIGURATIONSELECTION" Value="1" Secure="yes"/>
    <Property Id="FILEPATH" Admin="yes" Secure="yes" />
    ...
</Product>

然后定义CustomAction:

<Product>
...
    <Binary Id="CustomActions.CA" SourceFile="..\CustomActions\bin\
     $(var.Configuration)\CustomActions.CA.dll" />

    <CustomAction Id="CopyStartupConfig" Return="check" Execute="deferred" 
     BinaryKey="CustomActions.CA" DllEntry="CopyStartupConfig" />

...
</Product>

最后,请注意安装顺序。这样可以确保在最后完成此操作并且之前未安装产品,选择了第二个单选按钮并且实际选择了该文件。请注意,在此阶段技术上不需要文件路径检查,因为我在“下一步”按钮上进行验证,除非包含配置文件的文本框已填满,否则我不允许单击“下一步”按钮。

<InstallExecuteSequence>
  <Custom Action="CopyStartupConfig" Before="InstallFinalize">
    <![CDATA[NOT Installed AND CONFIGURATIONSELECTION = 2 AND FILEPATH <> ""]]>
  </Custom>
</InstallExecuteSequence>

...

至于自定义操作本身,它是一个简单的复制文件:

    [CustomAction]
    public static ActionResult CopyStartupConfig(Session session)
    {
        session.Log("CopyStartupConfig");
        try
        {
            string sourceFilename = session.CustomActionData["STARTUPCONFIG"];
            string targetFilename = Path.Combine(session.CustomActionData["APPLICATIONFOLDER"], Path.GetFileName(session.CustomActionData["STARTUPCONFIG"]));

            session.Log("SourceFileName: " + sourceFilename);
            session.Log("TargetFilename: " + targetFilename);

            session.Log("About to copy " + sourceFilename + " to " + targetFilename);
            File.Copy(sourceFilename, targetFilename);
            session.Log(sourceFilename + " copied successfully.");

            return ActionResult.Success;
        }
        catch (Exception ex)
        {
            session.Log("An unhandled exception has occured in CopyStartupConfig: " + ex.ToString());
            return ActionResult.Failure;
        }
    }

请记住,这是有效的,因为条件应用于InstallFinalize,并且两个变量都将按照我自己的方式设置,因为我正在调用我的自定义对话框,其中包括单选按钮,文件选择等...

上述内容似乎有效,但我显然需要花费更多时间对其进行测试,并且在卸载时我还必须注意删除配置文件的惯例。如果调用修复或更改,必须确保没有任何反应。

更新:我最初删除了我的答案,因为我发现它太晚了,它实际上并没有工作,我错过了将参数传递给我的自定义操作的关键部分。我认为这是自动完成的,但事实并非如此。

无论如何,在进一步研究这个问题后,我发现这篇文章非常清楚地解释了这个问题:

Creating Custom Action for WIX Written in Managed Code without Votive

所以这是缺失的部分:

您需要在自己的自定义操作中包含要传递给自定义操作的变量,并在每个值之间使用分号:

<CustomAction Id="SetCopyStartupConfigDataValue" Return="check"
              Property="CopyStartupConfig" Value="APPLICATIONFOLDER=
              [APPLICATIONFOLDER];STARTUPCONFIG=[FILEPATH]" />

现在确保在InstallSequence中包含此自定义操作,并将其设置为在调用复制操作之前触发:

<InstallExecuteSequence>
  <Custom Action="SetCopyStartupConfigDataValue" Before="CopyStartupConfig">
   NOT Installed</Custom>

  <Custom Action="CopyStartupConfig" Before="InstallFinalize">
    <![CDATA[NOT Installed AND CONFIGURATIONSELECTION = 2 AND FILEPATH <> ""]]>
  </Custom>
</InstallExecuteSequence>

最后一步是修改我的自定义操作。我已在上述代码中进行了更新,但简而言之,为了访问您已通过的变量,您不想使用session["STARTUPCONFIG"],而是想要使用会话session.CustomActionData["STARTUPCONFIG"]

希望这有帮助!

答案 1 :(得分:1)

你试过robocopy吗?我要求复制一些文件并且robocopy有帮助。

<CustomAction Id="ConfigureApp_Cmd" Property="ConfigureApp" Execute="immediate"
    Value="&quot;robocopy&quot; &quot;[FILEPATH]&quot; &quot;[INSDIR]&quot;" />
<CustomAction Id="ConfigureApp" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>

<InstallExecuteSequence>
    <Custom Action="ConfigureApp_Cmd" After="StartServices"><![CDATA[NOT(Installed)]]></Custom>
    <Custom Action="ConfigureApp" After="ConfigureApp_Cmd"><![CDATA[NOT(Installed)]]></Custom>
</InstallExecuteSequence>

如果必须清除目标位置,并且必须维护源目录结构,那么我们可以添加这些选项

<CustomAction Id="ConfigureApp_Cmd" Property="ConfigureApp" Execute="immediate"
    Value="&quot;robocopy&quot; &quot;[FILEPATH]&quot; &quot;[INSDIR]&quot; /PURGE /e" />
<CustomAction Id="ConfigureApp" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>

我假设FILEPATH是一个路径,当使用类似的东西调用安装程序时,该路径作为参数传递: msiexec / i FILEPATH = / qn / l * v install.log

让我知道这是否有效。