I was setting a property value inside a Dialog using Edit Control. But when i used the same property for writing inside an ini value it is not writing the updated value and writing only old value. My WIX source code is given below(writing only important codes as my wix code is too large)
<Property Id="testNumber" Value="1122" />
<CustomAction Id="SettestNumber" Property="ModifiedtestNumber" Value="[testNumber]" />
<ComponentGroup Id="INIFileGroup">
<Component Id="IniFile" Guid="{0ded271b-9268-49e7-8c13-60c7538acc25}" KeyPath="yes" Directory="DirCfg" >
<IniFile Id="IniPath" Action="addLine" Directory="Dirtest" Key="testkey" Name="test.ini" Section="test" Value="[ModifiedtestNumber]" />
</Component>
</ComponentGroup>
<InstallUISequence>
<Custom Action="SettestNumber" Sequence="1299"/>
</InstallUISequence>
<Dialog Id="testNumberUI" X="50" Y="50" Width="375" Height="270" Title="[ProductName]" CustomPalette="yes">
<Control Type="Edit" Id="test_Number" Width="50" Height="15" X="258" Y="53" Property="testNumber" Text="{50}" TabSkip="yes"/>
</Dialog>
I am giving the value 1212 in the Control edit box and installing but inside the test.ini file it is not getting updated and value is 1122. Could someone please provide a way for me to update the Modifedtestnumber to the ini file
Note:
When i put the Custom action inside < InstallExecuteSequence/> the value inside the ini file was null
Your property need to be public (all caps TESTNUMBER) and marked with Secure attribute so that it's listed in the SecureCustomPublicProperties property. Also be aware that properties are not persisted. You need to use something like the WiX remember property pattern for the value to be loaded from the INI file during subsequent transactions such as repairs and upgrades.
I have trouble with component in wix when I make update without ui.
<Component Id="PrinterConfEnable" Guid="911F0032-A217-4B1F-B973-29DB6DC06952">
<util:XmlFile Id="PrinterEnabled" Action="setValue" Permanent="yes" File="[INSTALLFOLDER]\config.xml" ElementPath="/printer/enabled" Value="true" />
<Condition>
<![CDATA[ USE_PRINTER_VAL = "1" and USE_PRINTER_0_VAL = "1" ]]>
</Condition>
</Component>
<Component Id="PrinterConfDisable" Guid="56AD5D4B-3700-44E1-9A0F-03E3A2A5D88F">
<util:XmlFile Id="PrinterDisabled" Action="setValue" Permanent="yes" File="[INSTALLFOLDER]\config.xml" ElementPath="/printer/enabled" Value="false" />
<Condition>
<![CDATA[ USE_PRINTER_VAL <> "1" or USE_PRINTER_0_VAL <> "1" ]]>
</Condition>
</Component>
During updating properties USE_PRINTER_VAL and USE_PRINTER_0_VAL are equal 1 but in config.xml it has been written
<printer>
<enabled>false</enabled>
</printer>
However when I update with UI it works properly
Assuming that these values are set in the UI, and "update without UI" means a feature change or patch (or something like that) then:
You are probably assuming that once property values are set in the UI they are saved somewhere for later use. They are not saved unless you save them, so they revert to the default values. WiX has a "remember property" pattern you can use to save the values so that the values originally entered will be saved and restored on other servicing activities like patches, updates etc.
http://robmensching.com/blog/posts/2010/5/2/the-wix-toolsets-remember-property-pattern/
Even if they are being set somewhere, they need be marked as secure to ensure that they pass correctly into the execute sequence.
I was trying to modify an .ini file in Wix
If it does not exists, the msi does not complete....
how do I check for this
I really want to modify it
Yes I looked at other stackoverflow questions/answers and on google
I was trying this...
<Component Id="TestIni" Guid="*">
<CreateFolder />
<IniFile Id="Ini1"
Action="createLine"
Directory="INSTALLLOCATION"
Section="Test"
Name="Minimal.ini"
Key="TestKey"
Value="TestValue" />
<IniFile Id="Ini2"
Action="createLine"
Directory="WindowsFolder"
Section="Test"
Name="Minimal.ini"
Key="TestKey"
Value="WindowsFolder TestValue" />
</Component>
Use Action="addLine" or Action="addTag" if you want to modify an existing value.
You could use the FileSearch element to set a property and then use this property in a condition.
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# application. In this file, I am using an element which is used to store multiple string values in an array. This is the content of the unaltered settings file:
<configuration>
<applicationSettings>
<AppName.Properties.Settings>
<setting name="StringArray" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</ArrayOfString>
</value>
</setting>
</AppName.Properties.Settings>
</applicationSettings>
</configuration>
I want to add <string> elements to the <ArrayOfString> element in this file. One way to do this is by using an <XmlConfig> element from the wix/UtilExtension namespace. I have added this element to the component which holds the config file like this:
<Component Id="ProductComponent" Guid="$(var.ConfigGuid)">
<File Source="SettingsFile.exe.config" KeyPath="yes" Id="FILE_config" />
<util:XmlConfig
Name="string"
Value="My value"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String1"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="100"
/>
</Component>
This results in the addition of one <string> element to the <ArrayOfString> element. To add another <string> element to the settings file, another XmlConfig element has to be added to the <Component> element of the setup project with a different Id attribute and a higher value for the Sequence attribute like this:
<util:XmlConfig
Name="string"
Value="My second value"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String2"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="101"
/>
After installation of the msi, the <ArrayOfString> element in the settings file looks like this:
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>My value</string><string>My second value</string></ArrayOfString>
I have found out that it is possible to set the Value attribute of an <XmlConfig> attribute to the value of a property like this:
<Property Id="STRING1VALUE" Value="My value" />
<util:XmlConfig Value="[STRING1VALUE]" ... />
This is good. I would like the user to be able to add multiple values in the installation process dynamically so that a variable amount of <string> elements can be added to the settings file.
My first approach was to use a <?foreach?> statement like this:
<?define values="My value;My second value"?>
<?foreach value in $(var.values)?>
<util:XmlConfig
Name="string"
Value="$(var.value)"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String$(var.value)"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="101"
/>
<?endforeach?>
There are a few problems with this approach:
The foreach statement uses a preprocessor variable which cannot be set to the value of a property.
The value of the Sequence attribute stays the same.
I would like the user to store the values for the string elements in a Property which separates the values by semicolons and then parse them in a foreach statement like this:
<Property Id="VALUES" Value="My value;My second value" />
<?foreach value in [VALUES]?>
<util:XmlConfig
Name="string"
Value="$(var.value)"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String$(var.value)"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="101"
/>
<?endforeach?>
This throws the following error:
The util:XmlConfig/#Id attribute's value, 'String[VALUES]', is not a legal identifier.
Identifiers may contain ASCII characters A-Z, a-z, digits, underscores (_), or periods (.).
Every identifier must begin with either a letter or an underscore.
Is there any way I can create a variable amount of elements with the XmlFile or the XmlConfig element? Is the only solution to this problem a CustomAction?
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.
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.
I need to use XmlConfig to modify my machine.config file during installation process, something like that:
<util:XmlConfig
Id="Machine_Config_Xml_Root"
File="[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config"
Action="create"
On="install"
ElementPath="//configuration/system.data/DbProviderFactories"
Name="add"
Node="element"
Sequence="1">
</util:XmlConfig>
<util:XmlConfig
Id="Machine_Config_Xml_4"
File="[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config"
ElementPath="Machine_Config_Xml_Root"
Name="name"
Value="My Data Provider"
Sequence="2">
</util:XmlConfig>
<util:XmlConfig
Id="Machine_Config_Xml_3"
File="[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config"
ElementPath="Machine_Config_Xml_Root"
Name="invariant"
Value="Sample.MyDataProvider"
Sequence="2">
</util:XmlConfig>
<util:XmlConfig
Id="Machine_Config_Xml_5"
File="[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config"
ElementPath="Machine_Config_Xml_Root"
Name="description"
Value="My Data Provider"
Sequence="2">
</util:XmlConfig>
<util:XmlConfig
Id="Machine_Config_Xml_2"
File="[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config"
ElementPath="Machine_Config_Xml_Root"
Name="type"
Value="Eli.Sample.MyDataProvider, Sample.MyDataProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5b9d34470b87a97f"
Sequence="2">
</util:XmlConfig>
<util:XmlConfig
Id="Machine_Config_Xml_Uninstall_1"
File="[WindowsFolder]Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config"
Action="delete"
On="uninstall"
ElementPath="//configuration/system.data/DbProviderFactories/add[\[]#invariant='Sample.MyDataProvider'[\]]"
Sequence="1">
</util:XmlConfig>
But it does not compile due to errors like this:
The localization variable !(loc.msierrXmlConfigFailedOpen) is unknown.
How can I define this loc.msierrXmlConfigFailedOpen variable and others? I don't want to switch to en-Us culture (in this case variables are defined) - I need to keep my current culture and define loc variables by myself. How can I do this and where on my wxs file should I put declarations?
This phrase you referenced can be found among UtilExtension texts. This is the relative path in WiX sources: /src/ext/UtilExtension/wixlib/en-us.wxl. As long as you reference the UtilExtension, and build the MSI for a different culture (not en-US), you get this error, because there's no translation of this and other phrases you pull along with UtilExtension.
You can do the following:
copy that en-us.wxl to your WiX sources and rename it to the culture you target
replace the values of <String> elements in that file with appropriate phrase translations for the culture you target
feed this file to light.exe (<localizations> section)
You might want to utilize the language fallback concept, described in "Specifying Cultures to Build" topic in WiX.chm