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.
你能指出如何安排我们的自定义操作来正确解密吗?
您的问题可能是由于以下原因之一造成的:
设置 CRYPTUNPROTECT_DATA
属性 的 <SetProperty>
元素有条件地 运行 基于 DB_PASSWORD
的值不是设置了,但是我们从日志中看不出这个属性确实没有设置。如果计算结果为 false,属性 操作将不会 运行。
<SetProperty>
元素上 Sequence
属性的默认设置无法正常工作。尝试将 Sequence
属性设置为 first
,这会将其安排在 InstallUISequence
或 InstallExecuteSequence
中的第一个 运行(在静音模式下将排在第一个).如果这不起作用,请尝试将其明确设置为 both
。
尝试将 InstallExecuteSequence
中 DecryptPassword
的自定义操作的 Before
属性更改为 After="InstallInitialize"
,这在安装顺序比 InstallFiles
。这将使您的行为类似于 运行 UI 序列,它会在实际安装任何内容之前计算和修改您的属性并 运行 执行您的操作。
请参阅 this page 以了解建议的顺序(并查看事件的相对顺序)
我们需要我们的 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.
你能指出如何安排我们的自定义操作来正确解密吗?
您的问题可能是由于以下原因之一造成的:
设置
CRYPTUNPROTECT_DATA
属性 的<SetProperty>
元素有条件地 运行 基于DB_PASSWORD
的值不是设置了,但是我们从日志中看不出这个属性确实没有设置。如果计算结果为 false,属性 操作将不会 运行。<SetProperty>
元素上Sequence
属性的默认设置无法正常工作。尝试将Sequence
属性设置为first
,这会将其安排在InstallUISequence
或InstallExecuteSequence
中的第一个 运行(在静音模式下将排在第一个).如果这不起作用,请尝试将其明确设置为both
。尝试将
InstallExecuteSequence
中DecryptPassword
的自定义操作的Before
属性更改为After="InstallInitialize"
,这在安装顺序比InstallFiles
。这将使您的行为类似于 运行 UI 序列,它会在实际安装任何内容之前计算和修改您的属性并 运行 执行您的操作。
请参阅 this page 以了解建议的顺序(并查看事件的相对顺序)