I have a registry key that can be equal to one of two values: special value or null. And two features.
When my registry key equals to special value the installer has to install first feature. if registry key is not found by registry search the installer has to install second feature. And if registry key has null value the installer must not install any of these two features.
What I'm doing or understanding wrong? If INSTALLLEVEL=5, SPECIALVALUE="special",MYTREAT="1" the first feature must be installed,but the installer doesn't install both of the features in this case.
<Feature Id="MyFeatures" Level="1" ConfigurableDirectory='INSTALLLOCATION' Display='expand' AllowAdvertise='no'>
<ComponentRef Id='Empty'/>
<Feature Id='First' Level='3' AllowAdvertise='no' ConfigurableDirectory='INSTALLLOCATION'>
<Condition Level="0">INSTALLLEVEL=4 OR (MYTREAT="1" AND NOT SPECIALVALUE AND NOT SPECIALVALUE="")</Condition>
<Condition Level="1">SPECIALVALUE="special" AND MYTREAT="1"</Condition>
<ComponentRef Id="first_comp"/>
</Feature>
<Feature Id="Second" Level="4" AllowAdvertise="no" ConfigurableDirectory="INSTALLLOCATION">
<Condition Level="0">INSTALLLEVEL=3 OR (MYTREAT="1" AND SPECIALVALUE)</Condition>
<ComponentRef Id="second_comp"/>
</Feature>
</Feature>
I had modified my code, but it's still not working right. Problem with conditions. There is a special value in registry key, but the installer is still skipping first feature. I had found that condition with just "MYTREAT=1" is not working. But in logs the client side is sending MYTREAT property with this value to the server.. INSTALLLEVEL is 1. MYTREAT property is initialized with pushbutton control,may be here is my trouble? Here new code:
<Feature Id="Myfeatures" Level="3"
ConfigurableDirectory='INSTALLLOCATION'
Display='expand' AllowAdvertise='no'>
<Condition Level='1'>MYTREAT="1"</Condition>
<ComponentRef Id='Empty'/>
<Feature Id='First' Level='3' AllowAdvertise='no'
ConfigurableDirectory='INSTALLLOCATION'> <!--Must be installed by default,default value of INSTALLLEVEL is 3-->
<Condition Level="1">MYTREAT="1" AND SPECIALVALUE="SPECIAL"</Condition>
<ComponentRef Id="first_comp"/>
</Feature>
<Feature Id="Second" Level="10" AllowAdvertise="no"
ConfigurableDirectory="INSTALLLOCATION"><!---->
<Condition Level="1">(MYTREAT="1" AND NOT SPECIALVALUE)</Condition>
<ComponentRef Id="second_comp"/>
</Feature>
</Feature>
............
<Dialog Id="TreatDlg" Width="260" Height="85">
<Control Id="Mytreat" Type="PushButton" X="50" Y="57" Width="56" Height="17" Property="MYTREAT">
<Publish Property="MYTREAT" Value="1">1</Publish>
<Publish Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
</Control>
P.S. I initialized MYTREAT with 1 by default and condition was evaluated correctly. Why I cannot use control's property in feature's condition? And how to resolve my problem!Please any help!
A common mistake is trying to control features through INSTALLLEVEL property. The install level should be static, you shouldn't change it during install.
The INSTALLLEVEL value is considered a level above which features are no longer installed. For example, if INSTALLLEVEL = 5 a feature with Level 4 will be installed and a feature with Level 6 will not be installed.
Through INSTALLLEVEL you can control the original feature state, for example:
<Feature Id="MyFeatures" Level="4" ConfigurableDirectory='INSTALLLOCATION' Display='expand' AllowAdvertise='no'>
<!-- Feature is not installed by default -->
<Feature Id='First' Level='6' AllowAdvertise='no' ConfigurableDirectory='INSTALLLOCATION'/>
<!-- Feature is installed by default -->
<Feature Id="Second" Level="4" AllowAdvertise="no" ConfigurableDirectory="INSTALLLOCATION"/>
</Feature>
For the above configuration you can then add install conditions by setting a Level lower or higher than INSTALLLEVEL:
<Feature Id="MyFeatures" Level="4" ConfigurableDirectory='INSTALLLOCATION' Display='expand' AllowAdvertise='no'>
<Feature Id='First' Level='6' AllowAdvertise='no' ConfigurableDirectory='INSTALLLOCATION'>
<Condition Level="4">(MYTREAT="1") AND (SPECIALVALUE="special")</Condition>
</Feature>
<Feature Id="Second" Level="4" AllowAdvertise="no" ConfigurableDirectory="INSTALLLOCATION">
<Condition Level="6">(INSTALLLEVEL = 3) OR (MYTREAT="1" AND SPECIALVALUE)</Condition>
</Feature>
</Feature>
As you can see, the feature Level attributes revolve around INSTALLLEVEL, not the other way around.
Edit:
Feature conditions are evaluated before any installation dialogs are shown. So you cannot condition a feature with a dialog control (for example a checkbox or a button).
A solution would be to use a custom action which modifies the feature action based on your custom property. For example you can use MsiSetFeatureState function. You can find a custom action tutorial here:
http://www.codeproject.com/KB/install/msicustomaction.aspx
Related
I am having issues getting my installer (msi) to remove a feature based component during uninstallation. The feature element, as per below, contains conditional component group references, which are to a directory id and a number of other components in another fragment (e.g., iis:WebAppPool):
Product.wxs
<Feature Id="StandardIntegration" Level="1" Title="StandardIntegration">
<ComponentGroupRef Id="SERVICES"/>
<!-- Integration Services IIS -->
<ComponentRef Id="comp1"/>
<ComponentRef Id="comp2"/>
<ComponentRef Id="comp3"/>
<ComponentRef Id="comp4"/>
<Condition Level="0">
<![CDATA[HAS_FEATURE_SET <> "true"]]>
</Condition>
</Feature>
OtherFragment.wxs
<DirectoryRef Id="INSTALLDIR">
<Directory Id="InstancePath">
<Directory Id="SERVICES" Name="Services"/>
</Directory>
</DirectoryRef>
<Component Id="comp1" Directory="SERVICES" Win64="yes" KeyPath="yes" Guid="$(var.c)" MultiInstance="yes" Shared="no">
<iis:WebAppPool Id="wbpoolid" ManagedRuntimeVersion="v4.0" Name="CMP_[NAME]" User="AppPoolUser" Identity="other" RecycleMinutes="0" RecycleRequests="0" ManagedPipelineMode="integrated">
</iis:WebAppPool>
....
All other components referred (including the ones that contains the iis web app pool element) are removed correctly during uninstallation, but the directory ("SERVICES") is not... and it's the only file directory that's not being removed. (E.g., all other files installed by the msi are being correctly removed.)
Any help would be much appreciated, thanks!
I'm trying to install a feature if the condition is true.
According to tutorials it should work like this:
<Feature Id='ParentFeature' Id='Default'
Title='Wix Sample App'
Description='The complete package of Wix Sample App.'
Display='expand'
Level='1'
ConfigurableDirectory='INSTALLDIR'>
<Feature Id='ChildFeature' Title='AppConfig Internal' Level='1'>
<ComponentRef Id='MyApp.exe' />
</Feature>
<!-- This is the conditional feature -->
<Feature Id='OptionalChildFeature' Title='AppConfig Internal' Level='0'>
<ComponentRef Id='MyApp.exe.config' />
<Condition Level='1'><![CDATA[TRUE]]></Condition>
</Feature>
</Feature>
My example results in NOT getting the optional feature installed, but I expected it to get installed.
The resources I used:
wix tutorial
stackoverflow question
Update:
I tried to make a prototype with which didn't work. finally worked and I could identify the problem in previous steps (a property was not correctly set).
You're condition of "TRUE" doesn't make sense. TRUE would be a public property called TRUE. Presumably, nothing set it to have a value so the condition evaluates to false and hence the feature remains at InstallLevel 0 and isn't installed.
I have a FeatureGroup in a Fragment that looks something like this:
<Fragment>
<FeatureGroup Id="ConsolidatedFeatureCollection">
<ComponentGroupRef Id="ComponentCollection" />
<Feature Id="Feature1" Title="Feature1" Level="1" AllowAdvertise="no" >
<ComponentRef Id="Component1" />
</Feature>
<Feature Id="Feature2" Title="Feature2" Level="1" AllowAdvertise="no" >
<ComponentRef Id="Component2" />
</Feature>
<Feature Id="Feature3" Title="Feature3" Level="1" AllowAdvertise="no" >
<ComponentRef Id="Component3" />
</Feature>
<Feature Id="Feature4" Title="Feature4" Level="1" AllowAdvertise="no" >
<ComponentRef Id="Component4" />
</Feature>
</FeatureGroup>
And I reference this FeatureGroup from my main feature like this:
<Feature Id="MainFeature" Title="Super Awesome Program" Level="1" AllowAdvertise="no" InstallDefault="local" Display="expand">
<FeatureRef Id="SomeOtherFeature"/>
<FeatureGroupRef Id="ConsolidatedFeatureCollection"/>
</Feature>
The FeatureGroup documentation says that it "groups together multiple components, features, and merges to be used in other locations." And the FeatureGroupRef documentation says that it is used to "create a reference to a FeatureGroup in another Fragment." It seems pretty straight forward, so I would expect that using this FeatureGroupRef as I have above would produce exactly the same result as using a FeatureRef for each individual Feature:
<Feature Id="MainFeature" Title="Super Awesome Program" Level="1" AllowAdvertise="no" InstallDefault="local" Display="expand">
<FeatureRef Id="SomeOtherFeature"/>
<FeatureRef Id="Feature1"/>
<FeatureRef Id="Feature2"/>
<FeatureRef Id="Feature3"/>
<FeatureRef Id="Feature4"/>
</Feature>
In fact, this seems to be exactly the purpose of the FeatureGroup element. Not so, when I use <UIRef Id="WixUI_FeatureTree"/> or any reference to the FeaturesDlg. Using the FeatureGroupRef, I cannot install individual Features. If any one of the Features in the group is selected, ALL are installed. You never see any indication of this in the UI, but they are installed.
I'm using the stable release of WIX toolset 3.8 (v3.8.1128.0), and I'm rather new to WIX, so I'm hesitant to assume that such a large bug has escaped the community for several months. Am I missing something about the way FeatureGroups work? And is there a work-around to allow selection of individual Features, other than a FeatureRef for every single Feature? (in real life, there are a lot more than four, and several projects which will use them)
I figured out what's wrong. It's a little embarrassing. ComponentCollection is the ComponentGroup that contains Component1, Component2, Component3, and Component4. I added that to the FeatureGroup because I thought that I needed to reference where these components are coming from. What I was actually doing was including all of the Components in the FeatureGroup. I was under the impression that a FeatureGroup simply contained Features, but apparently, it can install content of its own independent of its Features.
Once I removed <ComponentGroupRef Id="ComponentCollection" /> from the FeatureGroup, I started getting the behavior that I expected.
I've assigned a task in which one sub feature among 4 should be displayed to the user in the state as "This Feature Will Not be available"
For instance, I have this feature set:
<Feature Id="Main" AllowAdvertise="no" ConfigurableDirectory="MYROOT" Description="Required components" Display="expand" Level="1" Title="Main Feature" Absent="disallow">
<ComponentRef Id ="Cmp22"/>
<Feature Id="SubFeature_1" AllowAdvertise="no" Level="1">
</Feature>
<Feature Id="SubFeature_2" AllowAdvertise="no" Level="1">
</Feature>
<Feature Id="SubFeature_3" AllowAdvertise="no" Level="1">
<!-- I want this feature to displayed as "This Feature Will Not be available" -->
</Feature>
</Feature>
I've tried with different Level values.
Also, I used a VbScript custom action using Session.FeatureRequestState method, to change it at runtime, but can't get enough results.
Can someone please guide me about this?
Thanks and Best regards
Set the level to a value higher than INSTALLLEVEL property value:
http://msdn.microsoft.com/en-us/library/aa369536(VS.85).aspx
For example, if INSTALLLEVEL is 3, your feature level should be 4. To determine the INSTALLLEVEL value you can check the Property table in your MSI.
This might be a naive question. I have to manually edit a .WXS file to make it support select features from command line.
For example, there are 3 features in .WXS file.
<Feature Id="AllFeature" Level='1'>
<Feature Id="Feature1" Level='1'> </Feature>
<Feature Id="Feature2" Level='1'> </Feature>
<Feature Id="Feature3" Level='1'> </Feature>
</Feature>
Now, I want to select features from command line. Say, if I type "msiexec /i install.msi FEATURE=A", then "Feature1" and "Feature2" is installed; if I type "msiexec/i install.msi FEATURE=B", then "Feature1" and "Feature3" is installed. In this case, "A" maps to Feature 1 and 2; "B" maps to Feature 1 and 3.
How to accomplish this in WIX?
The accepted answer already mentions the ADDLOCAL property, but seems to imply that you can select only one feature. You can actually select multiple features by seperating them by commas like this:
msiexec /i install.msi ADDLOCAL=Feature1,Feature2
or
msiexec /i install.msi ADDLOCAL=Feature2,Feature3
Another hint: you can discover these feature names by opening the msi with orca. This is very useful when you want to use these tricks to create a bootstrapper that installs certain features of thirdparty msi packages.
I would change Feature1, Feature2 and Feature3 to Components, then would declare something like this:
<Feature Id="FEATUREA" Title="Super" Level="1" >
<ComponentRef Id="Component1" />
<ComponentRef Id="Component2" />
</Feature>
<Feature Id="FEATUREB" Title="Super1" Level="1" >
<ComponentRef Id="Component1" />
<ComponentRef Id="Component3"/>
</Feature>
Then to Install either FeatureA or FeatureB
msiexec /i install.msi ADDLOCAL=[FEATUREA | FEATUREB]
There are a number of properties that can control the install states of Features. Check out this MSI SDK documentation and the links from it: http://msdn.microsoft.com/en-us/library/aa367536(VS.85).aspx