Feature states in component conditions

MSI has some funky syntax to support checking the action state (what MSI is planning to do during the current install transaction) and install state (what MSI already did, in a previous install transaction) of both features and components. See Conditional Statement Syntax for the details and Examples of Conditional Statement Syntax for some examples. (As an aside, would it have been too much to ask to avoid the Perl-like prefix characters and have something function-like such as FeatureActionState(featureId)?)

A couple of people on the wix-users mailing list have asked about using the feature action state in component conditions. There’s good news and bad news.

Good news for simple cases

The good news is that in simple cases with simple conditions, there’s probably another way to get the behavior you’re looking for. For example, one component can be assigned to multiple features, so if you’re trying to install a component when any of several features are being installed, just reference the component in all the features. MSI will install the component once, regardless of how many features reference it.

The bad news

If you want to conditionalize a component based on whether a particular feature is being installed (i.e., its action state), you can’t rely solely on the component’s condition. The Component Table doc has this to say:

The Condition field enables or disables a component only during the CostFinalize action. To enable or disable a component after CostFinalize, you must use a custom action or the DoAction ControlEvent to call MsiSetComponentState.

The CostFinalize action doc says:

The CostFinalize action queries the Condition table to determine which features are scheduled to be installed. Costing is done for each component in the Component table.

Unfortunately, it doesn’t state explicitly that the order of the two sentences is the order of execution. But, even if it did, there’s this table in Conditional Statement Syntax:

Feature and Component State Values

The following table shows where it is valid to use the feature and component operator symbols.

Operator <state> Where this syntax is valid
$component-action In the Condition table, and in the sequence tables, after the CostFinalize action.
&feature-action In the Condition table, and in the sequence tables, after the CostFinalize action.
!feature-state In the Condition table, and in the sequence tables, after the CostFinalize action.
?component-state In the Condition table, and in the sequence tables, after the CostFinalize action.

So there are two fairly explicit strikes against being able to use a feature action state in a component condition:

  • Conditional Statement Syntax doesn’t list the Component table as a valid place to use the &feature-action syntax.
  • It says the syntax is valid only after CostFinalize but according to Component Table, that’s too late to use the component condition to enable/disable the component.

The Component Table says to use a “custom action or the DoAction ControlEvent to call MsiSetComponentState.” I haven’t quite deciphered whether the doc is saying to use DoAction to call a custom action from the UI or whether there’s a special, secret way of calling MsiSetComponentState via DoAction. If it’s the latter, I’m not aware of it (hence “special, secret”).

Here be dragons

Having been a writer for many years, I try to be nice about doc that is correct, even if in retrospect it’s not as helpful as it could have been. So here’s me being nice. The following sentence from Component Table easily leads a trusting reader down the wrong path:

The Condition column in the Component table accepts conditional expressions containing references to the installed states of features and components.

So here we have a sentence that contradicts the table in Conditional Statement Syntax and it’s really easy to misread the “installed state[s]” as “action states.” At the very least, it deserves clarification.

7 Replies to “Feature states in component conditions”

  1. Great article – but this article only covers the doumentation, have you been able to find a single example of how to do this at all? I not only have a component I’d like to be able to install based on another Feature’s state, but I also have a dialogbox I’d like the user to see ONLY if they install a Feature. I’m using InstallShield 2008, but I can do a direct-edit if I have to.

    Why isn’t this easier? I mean seriously, there have to be countless people like me who have a simple feature-based installer where, say, they have to install a SQL script, but if the user chooses not to install SQL script at that time, we *don’t need* a SQL script login dialog box.

    Please, leave a comment or drop me a line if you’ve seen examples of how precisely to do custom actions based on Feature states…

  2. Looks like it’s not possible to install a component only if a specific feature has been selected to install (using feature state in component condition)? How in this case people solve the problem?

  3. Sergey,

    It’s possible — just add the component to the feature. Components can be assigned to multiple features. The problem is in trying to use feature conditions for mutually-exclusive components. That doesn’t work.

  4. Thanks, Bob!

    Yes, components can be assigned to multiple features but this works as logical-OR (if at least one feature is selected the component will be installed). My scenario is a little bit different. The component (say ComponentA) is linked to feature Feature1. But i need to install it only if users select both Feature1 AND Feature2 so i add the following condition:

    &Feature2=3
    ...

    This doesn’t work (however Feature2 state is 3 for sure). Then i scheduled the following CA to run:


    NOT Installed AND

    which sets InstallFlag property (realy sets according to the log) so i can check it in the component’s condition like

    InstallFlag

    And this also doesn’t work 🙁 It only works if the property is predefined but i do need dynamic condition. What whould you suggest?

  5. Sorry, forgot to escape the code:

    <Component Id="ComponentA" Guid=".." KeyPath="yes">
    <Condition>&Feature2=3</Condition>
    ...

Comments are closed.