How can multiple elements be added to an XML config file with wix?

后端 未结 2 983
闹比i
闹比i 2021-02-09 22:23

I am trying to edit an XML file with Wix. I am using the WixUtilExtension bundled with Wix 3.7. The xml file is a settings file created in Visual Studio 2010 for a C# applicatio

相关标签:
2条回答
  • 2021-02-09 22:45

    Yes, this is possible but if you want to have this determined at install time then the preprocessor is not an option. The preprocessor executes during the build process.

    To get what you want, you'll need to write another custom action that takes the arbitrarily long set of user data and adds temporary rows to the XmlConfig table. The WcaAddTempRecord() function in src\ca\wcautil\wcawrap.cpp can do the work. The src\ca\wixca\dll\RemoveFoldersEx.cpp is a pretty good example of using WcaAddTempRecord() to add rows to the RemoveFile table. You'll want to do similarly.

    0 讨论(0)
  • 2021-02-09 22:54

    Based on Rob's answer, here is my new approach to adding multiple elements to an XML config file with Wix. I did not want to write C++ code, that is why I used DTF in my CustomAction.

    I am going to describe how to turn a string containing multiple elements using a delimiter into multiple XML elements.

    First there needs to be a property in the setup file containing the delimited string.

    <Property Id="STRINGARRAY" Value="string1;string2;string3" />
    

    This property could be populated by the user in a dialog, of course.

    Next, a CustomAction has to be written. To make use of the DTF, a reference to the Microsoft.Deployment.WindowsInstaller.dll has to be added to the C# CustomAction project. The namespace Microsoft.Deployment.WindowsInstaller should be included with a using directive in that 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, at first the Property StringArray is read into a local variable which is converted to a string array. The following line establishes a connection to the current database used by the installer. A handle on the table XmlConfig is created, which is the table where the XML elements are added to. To insert the right values into that table, it is best to create an installer file which contains such a table and then take a look at that table in an editor like orca or InstEd.

    In the xpath, backslashes have to be escaped by using double backslashes. The id variable holds the name of the temporary record, using a simple string and a number works flawlessly. The sequence has to be incremented for each element. I could not find any documentation on the values of the flags column, but I have found out that its value is set to 273 for elements that are created and 289 for elements that get deleted.

    Once the record is filled with the correct values, it gets added to the XmlConfig table by using the InsertTemporary method of the view object. This is done for each element found in the delimited string.

    A problem I have come across is that this CustomAction fails, if the XmlConfig table does not exist. To counter this problem I have added the following code to the setup file, which adds an element to the XML file and immediately deletes that element. I guess there could be a cleaner solution, but this was the easiest one 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, the CustomAction has to be added to the setup project. By adding a reference to the CustomAction project in the setup project, the location of the binary can be specified like this:

    <Binary Id="XmlCustomActionDLL" SourceFile="$(var.XmlCustomAction.TargetDir)XmlCustomAction.CA.dll" />
    

    The CustomAction has to be executed immediately, otherwise it won't 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>
    

    To determine the right position for the CustomAction in the installation sequence, I relied on this article by Bob Arnson.

    0 讨论(0)
提交回复
热议问题