In MSBuild we define properties within a PropertyGroup and reference them with the $() notation. In WiX we have variables with a similar syntax, but which do not natively map to MSBuild properties. When working with WiX installer projects within Visual Studio however you will often want to change a WiX variable into an MSBuild property and vice versa. For example:
- Case 1: You want to bubble through MSBuild properties (for example, assembly version) into the MSI (referenced within the WiX document with XPath locator //Product/@Version)
- Case 2: You need to call heat.exe with a custom SourceDir (using the -var parameter). For example, your project produces output files which you want deployed to different directory roots by a single MSI, so you successively harvest files for the various roots by calling heat.exe with a changing -var parameter.
The key things you need to know are:
- if you open a WiX project and select "Properties", then "Build", the "Define preprocessor variables" text box will inject a DefineConstants property into your project file; these variables are passed to candle.exe (among other things)
- if you open a WiX project and select "Properties", then "Build", the "Define variables" text box will inject a WiXVariables property into your project file; these variables are passed to light.exe (among other things)
- both the DefineConstants and WiXVariables MSBuild properties are semi-colon delimited lists of key/value pairs, and there are various methods -- more or less elegant -- of translating from one to the other
Transforming MSBuild properties into WiX variables (Case 1)
I think the most elegant way to do this is via the Decorator pattern here. This adds a new preprocessor variable derived from an MSBuild property without parsing out the existing ones by simply redefining DefineConstants and appending a new key/value pair to the end of it.
Transforming Wix variables into MSBuild properties (Case 2)
To do the opposite, you can extract a known WiX variable from a semi-colon delimited string of key/value pairs with a code snippet like this:
<!-- Convert the semicolon delimited list of key/vaue pairs into an ItemGroup -->
<!-- Evaluate each key/value pair with task batching, then make a conditional assignment -->
<Message Text="Environment is: $(ENVIRONMENT)"/>
Here we've used an ItemGroup to perform an implicit String.Split on the set of key/value constants within the DefineConstants property. We've then used Property functions to parse out the one we want, followed by a conditional assignment to grab just the value part.