1

我正在部署一个产品,其中包含一些配置 xml 文件中的加密字段。在安装过程中,我正在目标机器上创建一个自签名证书。然后我用它来加密一些字符串,最后我需要将它们存储在一个配置文件中。

为了创建证书,我将makecert.exe带到目标安装目录。因此,我需要等到所有文件都复制到它们的目的地,然后才能运行创建证书的 CustomAction。在此之后,其他一些 CustomAction 正在创建需要存储在配置中的加密值。

这很好用,但此时我想将新值存储在我的配置文件中,但我已经错过了执行 XmlFile/XmlConfig 的阶段。在 MSI 日志中,我看到在复制文件后立即执行了“ExecXmlConfig”操作:

MSI (s) (6C:CC) [02:12:10:898]: Source for file 'makecert.exe' is compressed
InstallFiles: File: makecert.exe,  Directory: C:\Program Files (x86)\MyProduct\InstanceFolder\,  Size: 60240
MSI (s) (6C:CC) [02:12:10:900]: Executing op: SetTargetFolder(Folder=C:\Program Files (x86)\MyProduct\Nhibernate\)
MSI (s) (6C:CC) [02:12:10:900]: Executing op: SetSourceFolder(Folder=1\o1lebnnf\vemzkq_g\|MyProduct\Nhibernate\)
MSI (s) (6C:CC) [02:12:10:901]: Executing op: FileCopy(SourceName=nw4bpvhi.xml|hibernate.cfg.xml,SourceCabKey=nhibernate.config,DestName=hibernate.cfg.xml,....
MSI (s) (6C:CC) [02:12:10:902]: File: C:\Program Files (x86)\MyProduct\Nhibernate\hibernate.cfg.xml;    Won't Overwrite;    Won't patch;    Existing file is unversioned but modified
MSI (s) (6C:CC) [02:12:10:902]: Executing op: SetTargetFolder(Folder=C:\Program Files (x86)\MyProduct\InstanceFolder\)
MSI (s) (6C:CC) [02:12:10:902]: Executing op: SetSourceFolder(Folder=1\o1lebnnf\|MyProduct\)
MSI (s) (6C:CC) [02:12:10:902]: Executing op: FileCopy(SourceName=7z64.dll,SourceCabKey=Seven7z64.dll,DestName=7z64.dll,Attributes=512,...
MSI (s) (6C:CC) [02:12:10:903]: File: C:\Program Files (x86)\MyProduct\InstanceFolder\7z64.dll; To be installed;    Won't patch;    No existing file
MSI (s) (6C:CC) [02:12:10:903]: Source for file 'Seven7z64.dll' is compressed
InstallFiles: File: 7z64.dll,  Directory: C:\Program Files (x86)\MyProduct\InstanceFolder\,  Size: 1484800
MSI (s) (6C:CC) [02:12:10:929]: Executing op: CacheSizeFlush(,)
MSI (s) (6C:CC) [02:12:10:929]: Executing op: ActionStart(Name=ExecXmlConfigRollback,,)
Action 02:12:10: ExecXmlConfigRollback. 
MSI (s) (6C:CC) [02:12:10:948]: Executing op: CustomActionSchedule(Action=ExecXmlConfigRollback,ActionType=3329,Source=BinaryData,Target=ExecXmlConfigRollback,...
MSI (s) (6C:CC) [02:12:10:949]: Executing op: ActionStart(Name=ExecXmlConfig,,)
Action 02:12:10: ExecXmlConfig. 
MSI (s) (6C:CC) [02:12:10:951]: Executing op: CustomActionSchedule(Action=ExecXmlConfig,ActionType=3073,Source=BinaryData,Target=ExecXmlConfig,CustomActionData=1?C:\Program Files (x86)\MyProduct\Nhibernate\hibernate.cfg.xml?3?0?/hibernate-configuration/session-factory/property[@name='connection.connection_string']????0)

所以我被困在两者之间......如果我将我的 CustomAction 配置为运行After='InstallFiles',它会在文件被复制之前很久就尝试执行。(我错过了正确的事件吗?)。另一方面,如果我将我的操作配置为运行After='InstallFinalize'- 为时已晚,因为 XmlConfig 已经触发并且没有向配置文件写入任何内容。理想情况下,我想在安装的最后运行所有这些。

我应该编写一个与 ExecXmlConfig 执行完全相同的操作的 CustomAction 只是为了在其他时间调用它,这似乎很愚蠢......

这是我的 InstallExecuteSequence:

    <InstallExecuteSequence>

      <!-- Create and Register Certificate on Install -->
      <Custom Action='GenerateProductCertificate'         After='InstallFiles'><![CDATA[REMOVE<>"ALL"]]></Custom>
      <Custom Action='RegisterProductServiceCertificate'  After='GenerateProductCertificate'><![CDATA[REMOVE<>"ALL"]]></Custom>

      <!-- Create and NHibernate Certificate -->      
      <Custom Action='GenerateNHibernateCertificate'      After='RegisterProductServiceCertificate'><![CDATA[REMOVE<>"ALL"]]></Custom>

      <!-- Configure NHibernate XML with Encrypted ConnectionString -->
      <Custom Action='GenerateSecureConnectionString'                   After='GenerateNHibernateCertificate'><![CDATA[(REMOVE<>"ALL")]]></Custom>

  </InstallExecuteSequence>

我正在使用 WiX 3.7(v3.7.1022.0,2012 年 10 月 22 日,星期一)

我的问题是:

  • 有没有办法重新安排 ExecXmlConfig 操作在我的 CustomActions 之后运行?
  • 如果没有,我可以安排我的 CustomAction 在复制文件和 ExceXmlConfig 之间运行吗?

编辑:

经过几次尝试和更多研究后,我可以更准确地定义我的问题。我想知道的是:如何设置延迟操作的输出值,该输出值可用于下一个延迟操作?

我的场景迫使我以延迟模式运行自定义操作,因此我无法访问 Session 来存储任何新变量。但我确信会安排更多的延迟操作,所以我想做的是找到一种方法将一些变量传递给它们。

4

1 回答 1

1

我目前正在构建的 msi 也出现了同样的问题。

如何设置延迟操作的输出值,该输出值可用于下一个延迟操作?

底线是我无法完全做到这一点。但是,我确实找到了一种通过其他自定义操作来解决它的方法。

我的情况略有不同,但希望有所帮助。对于这种情况,有一些注册表项必须更新,我希望保存以前的值以防回滚。我不能使用标准的 msi 注册表机制,因为值名称将取决于安装(我知道可能值的范围)。

我的自定义操作是二进制 dll 中基于 c++ 的代码。我的第一个想法是基于这样的假设,即一旦加载了 dll,它将保持不变,并且延迟执行序列中的所有调用都可以访问任何创建的数据结构。因此,我只是创建了一个全局变量并将必要的数据保存到其中。但是,在回滚调用期间,结构为空。似乎在每次调用 dll 之前,都会重新加载 dll。尽管我对它进行了足够的调查以看到 DllMain 被多次调用,但我并没有完全确认这一点。

我最终找到的解决方案是创建两个额外的自定义操作,它们在执行序列的脚本生成轮次中运行,一个用于安装,一个用于回滚。他们扫描了注册表并生成了一个分隔字符串,该字符串保存为 CustomActionData,用于相应的安装和回滚自定义操作。完成工作的延迟自定义操作被重写为仅执行通过 CustomActionData 告知的操作。所有“逻辑”(嗯,几乎所有)都在创建分隔字符串的代码中。

这似乎确实有效。我现在唯一有点担心的是,注册表扫描和注册表更新之间存在一些延迟和分离,出于美学目的,我想我试图避免这种情况。

不确定您是否可以在您的情况下做类似的事情。一种想法是也使用二进制 dll 来管理所有工作。它还将具有自定义操作,这些操作会根据您的第一个自定义操作的模拟输出生成 CustomActionData,然后您的第二个操作可以读取该输出。由于您的自定义操作涉及调用外部 exe,因此您可以使用 ShellExecute、System、CreateProcess 或类似方法来执行此操作。问题是您是否可以在不实际运行第一个自定义操作的情况下获得足够的信息。

于 2013-01-08T22:56:41.103 回答