ISWIX, LLC View Christopher Painter's profile on LinkedIn profile for Christopher Painter at Stack Overflow, Q&A for professional and enthusiast programmers

June 01, 2010

Improving InstallShield Product Configurations

InstallShield has a concept called "Product Configurations" that allows you to define similar yet different installers that generally contain different sets of features and metadata ( such as ProductCode, UpgradeCode, ProductName, ProductVersion ). It's a pretty powerful feature that uses flags to join products to features.

Consider the following:

Feature1
Flag 1

Feature2
Flag 2

Feature3
Flag 3

Product Configuration 1
Flag 1,3

Product Configuration 2
Flag 2,3

PC1 will get features 1 and 3 while PC 2 will get features 2 and 3.

Let's look at it another way:

Feature1
Flag A

Feature2
Flag B

Feature3
Flag A,B

Product Configuration 1
Flag A

Product Configuration 2
Flag B

Again, PC 1 will get features 1 and 3 while PC 2 will get features 2 and 3.

Make sense so far? Now here's where it falls apart IMO.

The flags are limited to 255 characters and when you scale to hundreds of features and dozens of products it's really easy to

a) run out of flag space
b) back yourself into a corner trying to figure out which products get which features based on which flags.
c) You are updating the installer source code every single time make a change for any of your products.

Basically it turns into a maintenance nightmare.

So here is I turn to a blend of WiX and InstallShield Automation to help solve the problem. Instead of declaring the product configurations in the Basic ISM project we split them out into WiX fragments that look like this:

WiX Config Files

<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define ProductConfiguration="1"?>
<!-- define other meta here -->
<FeatureRef Id="Feature1"/>
<FeatureRef Id="Feature3"/>
</Include>

<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define ProductConfiguration="2"?>
<!-- define other meta here -->
<FeatureRef Id="Feature2"/>
<FeatureRef Id="Feature3"/>
</Include>

You can then take this farther by the use of FeatureGroups's.

<?xml version="1.0" encoding="utf-8"?>
<Include>
<FeatureGroup Id="Client">
<FeatureRef Id="Feature1"/>
<FeatureRef Id="Feature3"/>
</FeatureGroup>
<FeatureGroup Id="Server">
<FeatureRef Id="Feature2"/>
<FeatureRef Id="Feature3"/>
</FeatureGroup>
</Include>

<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define ProductConfiguration="1"?>
<!-- define other meta here -->
<FeatureGroupRef Id="Client"/>
</Include>

<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define ProductConfiguration="2"?>
<!-- define other meta here -->
<FeatureGroupRef Id="Server"/>
</Include>

Build Automation

Since InstallShield doesn't 'do' WiX out of the box, the trick is to write a custom build automation step that parses the WiX XML documents and translates them into InstallShield source code using the COM Automation Interface. You can do this in any language that supports XML DOM parsing and COM. Personally I like like to use C# / .NET 3.5 with LINQ-To-XML for my DOM and a generated interop for the COM. Basically you have to parse the XML and walk the InstallShield project and wire it all up as if you had authored it all by hand.

I'll cover this part of it another day.

No comments: