Based on Rob's answer, here is my new approach to adding multiple elements to an XML configuration file using Wix. I did not want to write C ++ code, so I used DTF in my CustomAction.
I’ll show you how to turn a string containing multiple elements using a delimiter to multiple XML elements.
First, the installation file must have a property containing a delimited string.
<Property Id="STRINGARRAY" Value="string1;string2;string3" />
This property can be populated by the user in the dialog box, of course.
Then you need to write CustomAction. To use DTF, a link to the Microsoft.Deployment.WindowsInstaller.dll file must be added to the C # CustomAction project. The Microsoft.Deployment.WindowsInstaller namespace must be enabled using the using directive in this project. My CustomAction looks like this:
[CustomAction] public static ActionResult Insert(Session session) { string strings = session["STRINGARRAY"]; string[] stringArray = strings.Split(';'); Database db = session.Database; View view = db.OpenView("select * from `XmlConfig`"); string xpath = "/configuration/applicationSettings/AppName.Properties.Settings/setting[\\[]@name='StringArray'[\\]]/value/ArrayOfString"; for (int i = 0; i < stringArray.Length; i++) { string id = String.Format("String{0}", i); int sequence = 100 + i; string value = stringArray[i].Trim(); Record rec = new Record( id, "[INSTALLFOLDER]SettingsFile.exe.config", xpath, null, "string", value, 273, "ProductComponent", sequence); view.InsertTemporary(rec); } db.Close(); return ActionResult.Success; }
Here, first, the StringArray property is read into a local variable, which is converted to a string array. The next line connects to the current database used by the installer. An XmlConfig table handle is created, which is a table into which XML elements are added. To insert the correct values into this table, it is best to create an installer file that contains such a table, and then look at this table in an editor such as orca or InstEd.
In xpath, backslashes must be escaped with a double backslash. The id variable contains the name of the temporary record using a simple string, and the number works flawlessly. The sequence should be increased for each element. I could not find the documentation on the values of the flags column, but I found that for the values that were created, the values for its elements were set to 273 and 289 for elements that were deleted.
Once the record is filled with the correct values, it is added to the XmlConfig table using the InsertTemporary method of the view object. This is done for each item found in the separation line.
The problem I am facing is that this CustomAction fails if the XmlConfig table does not exist. To counter this problem, I added the following code to the installation file, which adds the element to the XML file and immediately removes this element. I suppose there might be a cleaner solution, but that was the easiest for me.
<util:XmlConfig Name="string" Value="Dummy" File="[INSTALLFOLDER]SettingsFile.exe.config" Id="DummyEntry" On="install" Action="create" Node="element" ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString" Sequence="1" /> <util:XmlConfig On="install" Action="delete" Id="DeleteDummyEntry" Node="element" File="[INSTALLFOLDER]SettingsFile.exe.config" VerifyPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString/string" ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString" Sequence="2" />
Finally, CustomAction should be added to the installation project. By adding a link to the CustomAction project in the installation project, the location of the binary file can be specified as follows:
<Binary Id="XmlCustomActionDLL" SourceFile="$(var.XmlCustomAction.TargetDir)XmlCustomAction.CA.dll" />
The CustomAction user must be executed immediately, otherwise he will not be able to access the session variable:
<CustomAction Id="CA_XmlCustomAction" BinaryKey="XmlCustomActionDLL" DllEntry="Insert" Execute="immediate" Return="check" /> <InstallExecuteSequence> <Custom Action="CA_XmlCustomAction" Before="RemoveRegistryValues" /> </InstallExecuteSequence>
In order to determine the correct position for CustomAction in the installation sequence, I relied on this article by Bob Arnson.