WiX [#filekey] is not allowed or used as a path in a managed custom application

I had a problem using deferred CustomAction, where the parameter is passed as a link to a file identifier in the style of [# file.Product.exe.config]:

<Component Id="comp.Product.exe.config" Guid="{966DA007-E3F0-4BFE-94ED-63A66F82CA58}" Win64="$(var.Win64)"> <File Id="file.Product.exe.config" Name="Product.exe.config" Source="$(var.SourcePath)\Product.exe.config" KeyPath="yes" /> </Component> 

Then I have a property called ConfigurationFile, which is later passed to the deferred user action, for example:

 <Property Id="ConfigurationFile" Value="[#file.Product.exe.config]" /> 

I previously assigned the ConfigurationFile Value = "[APPLICATIONROOTDIRECTORY] \ Product.exe.config" property, which worked fine, but since we need to install the configuration in a different folder (the reason why this should have been done does not matter to this topic), I had to modify it to allow the location of the configuration file from the installer using the syntax [#file.Product.exe.config] .

When a user action receives this parameter, it is still in the format [#file.Product.exe.config] (that is, not resolved) and causes a lot of problems. I was a little embarrassed because, based on registration, it seemed like it should work. It turns out that Session.Log( ) resolves this link to the file, which led to the journal "lying" to me about the actual content of the argument.

I tried different approaches to the "clan" of this line, including session.Format() which leads to an InvalidHandleException, using a record (as indicated below) and other ways without luck.

 using (Record formatRec = new Record(0)) { formatRec.FormatString = p0; return formatRec.GetString(0) // Or formatRec.ToString(); } 

WiX has several user actions that handle this agreement. However, I have yet to figure out how they do it. Until you can dive into the source code for these custom actions.

User action arguments are retrieved from Session.CustomActionData .

Is there a good way to handle this?

+4
source share
2 answers

After a few gray hair and a rather coarse tongue, I came up with a solution. It is based on @Zachary Youngs answer, however some changes were needed.

Using pending action does not allow access to properties. Using the action as an immediate action of type 51 to set the property made the [#filekey] link remain intact.

Using the following solution works:

 <!-- Custom action to set update [ConfigurationFile] to the resolved filename --> <CustomAction Id="SetResolvedConfigurationFile" BinaryKey="LocusCA" DllEntry='SetResolvedConfigurationFile' Return="check" Execute="immediate" /> <!-- Set CustomActionData for MergeConfiguratioFiles custom action --> <CustomAction Id="SetMergeConfigurationFiles" Property="MergeConfigurationFiles" Execute="immediate" Value="[ConfigurationFile]" /> <!-- Merge settings from old configuration file to the one being installed --> <CustomAction Id='MergeConfigurationFiles' BinaryKey="LocusCA" DllEntry='MergeConfigFiles' Return="check" Execute="commit" /> <InstallExecuteSequence> <Custom Action="SetResolvedConfigurationFile" Before="InstallFinalize">NOT (WIX_UPGRADE_DETECTED = "") AND NOT (ConfigurationFile = "")</Custom> <Custom Action="SetMergeConfigurationFiles" After="SetResolvedConfigurationFile">NOT (WIX_UPGRADE_DETECTED = "") AND NOT (ConfigurationFile = "")</Custom> <Custom Action="MergeConfigurationFiles" After="SetMergeConfigurationFiles">NOT (WIX_UPGRADE_DETECTED = "") AND NOT (ConfigurationFile = "")</Custom> </InstallExecuteSequence> 

The custom action SetResolvedConfigurationFile is as follows:

 [CustomAction] public static ActionResult SetResolvedConfigurationFile(Session session) { // Set property ResolvedConfigurationFile try { session["ConfigurationFile"] = session.FormatRecord(new Record(1) { FormatString = session["ConfigurationFile"] }); } catch (Exception ex) { session.Log("Unable to find configuration file for merge from property 'ConfigurationFile'): " + ex); return ActionResult.Failure; } return ActionResult.Success; } 

Using session.FormatRecord to resolve the current [ConfigurationFile] value and write it back to the property, an existing setting of my user action will be created.

Note: using a shortcut to change my MergeConfigurationFile action for immediate execution does not work, since the files I need to merge do not exist yet. Using session.FormatRecord directly in the MergeConfigurationFile throws an InvalidHandleException when trying to format while executing Execute = "commit" and using Record.ToString () or Record.GetString () just returns the link [#filekey].

+1
source

To set a property, you need a custom action of type 51 :

 <CustomAction Id="SetProductConfigPath" Property="ConfigurationFile" Value="[#file.Product.exe.config]" Execute="deferred"/> <InstallExecute> <Custom Action="SetProductConfigPath" Before="InstallInitialize">/> </InstallExecute> 

You may need to configure the schedule for something other than "InstallInitialize".

See the blog post From MSI to WiX, Part 5 - User Actions: An Introduction to a List of All Types of CustomAction and a Blog Post The property does not exist or is empty when accessed from deferred user actions for a detailed explanation of deferred user actions.

Hope this helps.

+4
source

Source: https://habr.com/ru/post/1401011/


All Articles