WiX CustomAction 在 UI 中触发但不在执行序列中触发

WiX CustomAction fires in UI but not Execute Sequence

我们需要我们的 MSI 将密码存储在注册表中,以便用户可以使用我们的安装程序更改连接字符串等。

我们找到了 MsiExt 的加密 DLL,并正在尝试配置自定义操作。

我们的用户需要能够通过 UI 对话框和静默方式进行安装——所以我们需要能够按这两种顺序执行。

这是我们的示例 Product.wxs

    <Property Id="DB_PASSWORD" Secure="yes"/>
    <Property Id="P.DB_PASSWORD">
      <RegistrySearch Id="S.DB_PASSWORD" Root="HKLM" Key="SOFTWARE$(var.Manufacturer)$(var.ProductName)" Name="DB_PASSWORD" Type="raw" Win64="$(var.Win64)"/>
    </Property>

    <Component Id="c.RegistryEntries" Guid="XXXXX-XXXXX-XXXXX-XXXXX" Directory="INSTALLDIR">
      <RegistryKey Root="HKLM" Key="SOFTWARE$(var.Manufacturer)$(var.ProductName)" Action="createAndRemoveOnUninstall">
        <RegistryValue Id="R.DB_PASSWORD" Name="DB_PASSWORD" Value="[ENCRYPTED_DBPASSWORD]" Type="string" />
      </RegistryKey>
    </Component>

    <!--For encrypting the database password on the way to the registry-->
    <Binary Id="Cryptography" SourceFile="..\..\lib\msiext-1.4\CustomActions\Cryptography.dll"/>

    <!--This property will receive the encrypted DB_PASSWORD that the user enters and will be encrypted-->
    <Property Id="CRYPTPROTECT_DATA" Hidden="yes" />

    <Property Id="CRYPTPROTECT_FLAGS" Value="CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN" />
    <CustomAction Id="EncryptPassword" BinaryKey="Cryptography" DllEntry="CryptProtectDataHex" Execute="immediate" />
    <CustomAction Id="SetDBUSERsPASSWORDForEncryption" Property="CRYPTPROTECT_DATA" Value="[DB_PASSWORD]" />
    <Property Id="ENCRYPTED_DBPASSWORD" Hidden="yes" />
    <SetProperty Id="ENCRYPTED_DBPASSWORD" Value="[CRYPTPROTECT_RESULT]" Sequence="execute" After="SetDBUSERsPASSWORDForEncryption" />

    <!--This is for decrypting the registry value-->
    <Property Id="CRYPTUNPROTECT_DATA" Hidden="yes" />
    <Property Id="CRYPTUNPROTECT_FLAGS" Value="CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN" />
    <SetProperty Id="CRYPTUNPROTECT_DATA" Value="[P.DB_PASSWORD]" Before="DecryptPassword" >NOT(DB_PASSWORD)</SetProperty>
    <CustomAction Id="DecryptPassword" BinaryKey="Cryptography" DllEntry="CryptUnprotectDataHex" Execute="firstSequence" />
    <CustomAction Id="SetDBUSERsDecryptedPASSWORD" Property="DB_PASSWORD" Value="[CRYPTUNPROTECT_RESULT]"/>

    <CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
    <InstallUISequence>
      <Custom Action="DecryptPassword" After="CostFinalize"><![CDATA[NOT(DB_PASSWORD)]]></Custom>
      <Custom Action="SetDBUSERsDecryptedPASSWORD" After="DecryptPassword" ><![CDATA[NOT(DB_PASSWORD)]]></Custom>
    </InstallUISequence>
    <InstallExecuteSequence>
      <Custom Action="SchedXmlConfig" After="InstallFiles"><![CDATA[(NOT REMOVE~="All")]]></Custom>
      <Custom Action="SetDBUSERsPASSWORDForEncryption" Before="InstallInitialize" />
      <Custom Action="EncryptPassword" After="SetDBUSERsPASSWORDForEncryption" />

      <Custom Action="DecryptPassword" Before="InstallFiles"><![CDATA[CRYPTUNPROTECT_RESULT]]></Custom>
      <Custom Action="SetDBUSERsDecryptedPASSWORD" After="DecryptPassword" ><![CDATA[CRYPTUNPROTECT_RESULT]]></Custom>

    </InstallExecuteSequence>

安装日志显示 DecryptPassword 在 UI序列期间触发。解密自定义操作触发,然后 DecryptPassword 起作用。

Action ended 17:52:43: CostFinalize. Return value 1.
MSI (c) (CC:A8) [17:52:43:936]: Doing action: SetCRYPTUNPROTECT_DATA
Action 17:52:43: SetCRYPTUNPROTECT_DATA. 
Action start 17:52:43: SetCRYPTUNPROTECT_DATA.
MSI (c) (CC:A8) [17:52:43:937]: PROPERTY CHANGE: Adding CRYPTUNPROTECT_DATA property. Its value is '**********'.
Action ended 17:52:43: SetCRYPTUNPROTECT_DATA. Return value 1.
MSI (c) (CC:A8) [17:52:43:937]: Doing action: DecryptPassword
Action 17:52:43: DecryptPassword. 
Action start 17:52:43: DecryptPassword.
MSI (c) (CC:7C) [17:52:49:129]: Invoking remote custom action. DLL: C:\Users\kujotx\AppData\Local\Temp\MSI9904.tmp, Entrypoint: CryptUnprotectDataHex
MSI (c) (CC:54) [17:52:49:130]: Cloaking enabled.
MSI (c) (CC:54) [17:52:49:130]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (CC:54) [17:52:49:130]: Connected to service for CA interface.
CryptUnprotectDataHex: MSI Extensions 1.4.1114.0
MSI (c) (CC!94) [17:52:49:236]: PROPERTY CHANGE: Adding CRYPTUNPROTECT_RESULT property. Its value is 'password'.
Action ended 17:52:49: DecryptPassword. Return value 1.
MSI (c) (CC:A8) [17:52:49:238]: Doing action: SetDBUSERsDecryptedPASSWORD
Action 17:52:49: SetDBUSERsDecryptedPASSWORD. 
Action start 17:52:49: SetDBUSERsDecryptedPASSWORD.
MSI (c) (CC:A8) [17:52:49:239]: PROPERTY CHANGE: Adding DB_PASSWORD property. Its value is '**********'.
Action ended 17:52:49: SetDBUSERsDecryptedPASSWORD. Return value 1.

我的问题是 SetCRYPTUNPROTECT_DATA 在 ExecuteSequence 期间没有执行,所以 DecryptPassword 失败:

Action ended 17:53:47: AppSearch. Return value 1.
MSI (s) (28:1C) [17:53:47:206]: Doing action: DecryptPassword
Action 17:53:47: DecryptPassword. 
Action start 17:53:47: DecryptPassword.
MSI (s) (28:98) [17:53:47:217]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI9020.tmp, Entrypoint: CryptUnprotectDataHex
CryptUnprotectDataHex: MSI Extensions 1.4.1114.0
CryptUnprotectDataHex: [CryptUnprotectDataHex] std::exception: 0x80070057 - Error in CryptUnprotectData: The parameter is incorrect.
MSI (s) (28!DC) [17:53:47:237]: PROPERTY CHANGE: Adding CA_ERROR property. Its value is '0x80070057 - Error in CryptUnprotectData: The parameter is incorrect.'.
CustomAction DecryptPassword returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 17:53:47: DecryptPassword. Return value 3.
Action ended 17:53:47: INSTALL. Return value 3.

你能指出如何安排我们的自定义操作来正确解密吗?

您的问题可能是由于以下原因之一造成的:

  1. 设置 CRYPTUNPROTECT_DATA 属性 的 <SetProperty> 元素有条件地 运行 基于 DB_PASSWORD 的值不是设置了,但是我们从日志中看不出这个属性确实没有设置。如果计算结果为 false,属性 操作将不会 运行。

  2. <SetProperty> 元素上 Sequence 属性的默认设置无法正常工作。尝试将 Sequence 属性设置为 first,这会将其安排在 InstallUISequenceInstallExecuteSequence 中的第一个 运行(在静音模式下将排在第一个).如果这不起作用,请尝试将其明确设置为 both

  3. 尝试将 InstallExecuteSequenceDecryptPassword 的自定义操作的 Before 属性更改为 After="InstallInitialize",这在安装顺序比 InstallFiles。这将使您的行为类似于 运行 UI 序列,它会在实际安装任何内容之前计算和修改您的属性并 运行 执行您的操作。

请参阅 this page 以了解建议的顺序(并查看事件的相对顺序)