How to use conditions in features in WiX? - wix

I am trying to make simple Windows intaller, and I don't know how to deal with this.
I have two features - feature1 and feature2. I want feature2 to be installed only if the user selected feature1 to be installed. So I tried:
<Feature Id='core' Title='Core'
Description='ØMQ 1.0.0 core functionality and C++ API' Level='1'>
<ComponentRef Id='Core_include' />
<ComponentRef Id='Core_bin' />
<ComponentRef Id='Core_lib' />
<ComponentRef Id='Core_zmq' />
<ComponentRef Id='cpp_bin' />
</Feature>
<Feature Id='core_perf' Title='core_perf' Description='0MQ core perf' Level='999'>
<Condition Level="0">NOT (&core = "3")</Condition>
<ComponentRef Id='cpp_perf' />
</Feature>
But this doesn't install feature core_perf if the user selects feature core.
How can I fix this?

You need to move your Condition into your Component definition, and use ! (Feature state) instead of & (Feature action) so that it works when you try to add the examples by re-running the install a second time:
<Component Id="example1">
<Condition>!feature1 = 3</Condition>
</Component>
<Component Id="example2">
<Condition>!feature2 = 3</Condition>
</Component>
<Feature Id="feature1">
</Feature>
<Feature Id="feature2">
</Feature>
<Feature Id="examples">
<ComponentRef Id="example1" />
<ComponentRef Id="example2" />
</Feature>

Have you considered making feature1 the parent of feature2? Then feature2 can't be installed unless feature1 will also be installed. No condition necessary.
<Feature Id='core' Title='Core'
Description='ØMQ 1.0.0 core functionality and C++ API' Level='1'>
<ComponentRef Id='Core_include' />
<ComponentRef Id='Core_bin' />
<ComponentRef Id='Core_lib' />
<ComponentRef Id='Core_zmq' />
<ComponentRef Id='cpp_bin' />
<Feature Id='core_perf' Title='core_perf' Description='0MQ core perf'
Level='999'>
<ComponentRef Id='cpp_perf' />
</Feature>
</Feature>

Related

WiX installing unselected features

I'm in the process of using WiX to create an install package with multiple features. It's using the Mondo UI to allow the user to select one or more features to install. The problem I'm having is that it's always installing all features, regardless of what the user selects.
Below is my WXS file:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="Setup Test 1" Language="1033" Version="1.0.0.0" Manufacturer="dbush" UpgradeCode="MYGUID="yes" InstallScope="perMachine" Comments="testing the installer" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="all" Title="all features" Description="everything" Level="1" Display="expand">
<Feature Id="file1" Title="file1" Description="file1.txt" Level="1">
<ComponentGroupRef Id="file1" />
</Feature>
<Feature Id="file2" Title="file2" Description="file2.txt" Level="10">
<ComponentGroupRef Id="file2" />
</Feature>
<Feature Id="regkey" Title="registry key" Description="registry properties to install" Level="11">
<ComponentGroupRef Id="regkey" />
</Feature>
</Feature>
<Property Id="PROP1" Value="replacement" />
<UIRef Id="WixUI_Mondo" />
<UIRef Id="WixUI_ErrorProgressText" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="setup_test_1" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="file1" Directory="INSTALLFOLDER">
<Component Id="file1.txt" Guid="MYGUID">
<File Id="file1.txt" Source="src/file1.txt" />
</Component>
</ComponentGroup>
<ComponentGroup Id="file2" Directory="INSTALLFOLDER">
<Component Id="file2.txt" Guid="MYGUID">
<File Id="file2.txt" Source="src/test2.txt" />
</Component>
</ComponentGroup>
<ComponentGroup Id="regkey" Directory="INSTALLFOLDER">
<Component Id="reg_key_1">
<RegistryValue Root='HKCU' Key='SOFTWARE\setup_test_1\properties'
Name='prop1' Value='[PROP1]'
Type='string' />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
What could be causing this?
I'm using WiX toolset 3.11.2 and Visual Studio 2017.
This was caused by the main Feature element having Id="all". Changing it to some other string such as "everything" allowed for individual features to be installed.
I wasn't able to find any documentation on why an Id with this name is a special case.

WiX root feature without Treelines

Is it possible to have the root feature in the feature tree to not have tree lines so you can't expand and collapse it?
So the following feature tree:
<Feature Id="root" Level ="1" Title="Root" Display="expand" AllowAdvertise="no"
ConfigurableDirectory="INSTALLDIR" Absent="disallow" TypicalDefault="install"
InstallDefault="local">
<Feature Id="child1" Title="Child 1"
Level="1" Display="expand" AllowAdvertise="no"
InstallDefault="local" >
<ComponentGroupRef Id="SharedComponents" />
</Feature>
<Feature Id="child2" Title="Child 2"
Level="1" Display="expand" AllowAdvertise="no"
InstallDefault="local" >
<ComponentGroupRef Id="SharedComponents" />
</Feature>
<Feature Id="childgroup1" Title="Child Group 1"
Level="1" Display="expand" AllowAdvertise="no"
InstallDefault="local" >
<Feature Id="groupchild1" Title="Child 1"
Level="1" Display="expand" AllowAdvertise="no"
InstallDefault="local" >
<ComponentGroupRef Id="SharedComponents" />
</Feature>
<Feature Id="groupchild2" Title="Child 2"
Level="1" Display="expand" AllowAdvertise="no"
InstallDefault="local" >
<ComponentGroupRef Id="SharedComponents" />
</Feature>
</Feature>
</Feature>
Gives me this:
But I'd rather not have the tree lines on the root element.
External GUI: I don't know of any way to remove the dotted lines, short of using an external GUI - which is possible (see this answer).
Hide Features: You can, however, set features to be hidden, in which case the sub-features won't show either. I am not sure exactly what you want.
Feature Four is hidden:
<Feature Id="One" Title="One" Level="1" >
<Feature Id="Two" Title="Two" Level="1"/>
<Feature Id="Three" Title="Three" Level="1">
<Feature Id="ThreeOne" Title="ThreeOne" Level="1" >
</Feature>
<Feature Id="Four" Title="Four" Level="1" Display="0" />
</Feature>
</Feature>
MSI GUI: For the record I should point out that the MSI GUI is an old relic by now from a bygone era of computing (late 90s). As such the GUI isn't that easy to do much about, except to replace the whole thing as described in the link above(and from the MSI SDK: MsiSetExternalUI).
Tools such as Installshield and Advanced Installer will allow you to use template GUIs with more modern features, and WiX allows you to write your own GUI entirely as well: WIX Installer with modern look and feel (same link as above).
All the custom GUIs are based on the MsiSetExternalUI MSI API (as far as I know).

How to remove "Will be installed to run from network" installation options from MSI when using WiX?

Bear with me, I'm just trying to learn WiX. I'm curious how to remove the following network installation options from this popup menu (circled in red)?
EDIT: As requested below, here's the Feature node:
<Feature Id='Complete' Title='Product title' Description='The complete package.'
Display='expand' Level='1' ConfigurableDirectory='INSTALLDIR' Absent='disallow' AllowAdvertise='no' >
<Feature Id='MainProgram' Title='Program files'
Description='Installs the main executable files for the software.'
Absent='disallow'
AllowAdvertise='no'
Level='1'>
<ComponentRef Id='CompIDFile1EXE' />
<ComponentRef Id='CompIDFile2EXE' />
<ComponentRef Id='CompIDFile3EXE' />
<ComponentRef Id='CompIDFile1DLL' />
<ComponentRef Id='CompIDFile2DLL' />
<ComponentRef Id='CompIDMainRegistry' />
<ComponentRef Id='ProgramMenuDir' />
</Feature>
<Feature Id='ShortcutsStart' Title='Start Menu Shortcuts'
AllowAdvertise='no'
Description="Places software shortcuts into the Windows Start Menu."
Level='1'>
<ComponentRef Id='CompIDShortcutsStart' />
</Feature>
<Feature Id='ShortcutsDesktop' Title='Desktop Shortcut'
AllowAdvertise='no'
Description="Places software shortcut onto the users' desktops."
Level='1000'>
<ComponentRef Id='CompIDShortcutsDesktop' />
</Feature>
</Feature>
You should show your WiX source being used for the Feature elements. It's most likely a combination of the InstallDefault setting (which you probably want to be "local") and AllowAdvertise (and set it to "no").
For features that do not directly contain ComponentRef or ComponentGroupRef, you just create a dummy component inside that feature with a Location="local" attribute. This will get rid of the "run from network" options.
Example:
<Feature Id='Complete' Title='Product title' Description='The complete package.' Display='expand' Level='1' ConfigurableDirectory='INSTALLDIR' Absent='disallow' AllowAdvertise='no' >
<!-- Dummy component to get rid of the "run from network" option -->
<Component Id="CompleteDummyComponent" Location="local" Directory="TARGETDIR" Guid="GUID_HERE_PLEASE" />
<!-- sub features here -->
</Feature>

Using a WiX Selection Tree control, when I select Feature 1, I want Feature 2 to be selected automatically

I have three features in a Selection Tree control. I would like Feature 2 and 3 to be independently selected and installed but if Feature 1 is selected to be installed I want Feature 2 to be automatically selected since Feature 1 depends on it. When my Selection Tree is displayed I see:
[-] All Features
[x] Feature 1 (requires Feature 2)
[x] Feature 2
[x] Feature 3
Where [-] represents the icon for "Will be installed on local hard drive"
and [x] represents the icon for "Entire feature will be unavailable".
When I select Feature 1 to be installed I see:
[-] All Features
[-] Feature 1 (requires Feature 2)
[x] Feature 2
[x] Feature 3
But when I select Feature 1, I want Feature 2 to be selected automatically so it would look like this:
[-] All Features
[-] Feature 1 (requires Feature 2)
[-] Feature 2
[x] Feature 3
I don't want Feature 3 to be automatically selected since it is not required by Feature 1. Is there a way to do this? This seems like a simple problem but I could not find any documentation or examples on how to do this. I have tried to use a condition within Feature2 like the following but the condition never gets tested since only Feature 1 was selected:
<Feature Id="ProductFeature" Title="All Features" Display="expand" Level="1">
<Feature Id="Feature1" ConfigurableDirectory="APPLICATIONFOLDER"
Title="Feature 1 (requires Feature 2)" Level="2">
<ComponentRef Id="file1.txt" />
</Feature>
<Feature Id="Feature2" ConfigurableDirectory="APPLICATIONFOLDER"
Title="Feature 2" Level="2">
<ComponentRef Id="file2.txt" />
<Condition Level="1">MsiSelectionTreeSelectedFeature="Feature1"</Condition>
</Feature>
<Feature Id="Feature3" ConfigurableDirectory="APPLICATIONFOLDER"
Title="Feature 3" Level="2">
<ComponentRef Id="file3.txt" />
</Feature>
</Feature>
If only Feature 1 is selected, is there a way to "tell it" to set the Level attribute of Feature2 to 1 so that Feature 2 in the Selection Tree displays the icon showing it will be installed also? If trying to set the Level attribute of Feature2 is not the right approach, is there another method I can use to accomplish the behavior I desire?
Here is my full program if you want to try it:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="41788c15-290e-426f-934e-e5b3bf875013" Name="WixUI_FeatureTree"
Language="1033" Version="1.0.0.0" Manufacturer="WixUI_FeatureTree"
UpgradeCode="5f5d4f80-96f5-4060-a718-539b547d8a29">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<?define FeatureTree=1?>
<UIRef Id="MyWixUI_FeatureTree" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONFOLDER" Name="WixUI_FeatureTree">
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONFOLDER">
<Component Id="file1.txt" Guid="FEBD6C0C-1BDF-413C-B7B1-A4E18AC7A6FA">
<File Id="file1.txt" Source="file1.txt" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="file2.txt" Guid="FEBD6C0C-1BDF-413C-B7B1-A4E18AC7A6FB">
<File Id="file2.txt" Source="file2.txt" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="file3.txt" Guid="FEBD6C0C-1BDF-413C-B7B1-A4E18AC7A6FC">
<File Id="file3.txt" Source="file3.txt" KeyPath="yes" Checksum="yes"/>
</Component>
</DirectoryRef>
<Feature Id="ProductFeature" Title="All Features" Display="expand" Level="1">
<Feature Id="Feature1" ConfigurableDirectory="APPLICATIONFOLDER"
Title="Feature 1 (requires Feature 2)" Level="2">
<ComponentRef Id="file1.txt" />
</Feature>
<Feature Id="Feature2" ConfigurableDirectory="APPLICATIONFOLDER"
Title="Feature 2" Level="2">
<ComponentRef Id="file2.txt" />
<Condition Level="1">MsiSelectionTreeSelectedFeature="Feature1"</Condition>
</Feature>
<Feature Id="Feature3" ConfigurableDirectory="APPLICATIONFOLDER"
Title="Feature 3" Level="2">
<ComponentRef Id="file3.txt" />
</Feature>
</Feature>
</Product>
</Wix>

Wix database script execute depending on chosen features on FeatureTree

I my installer I want to run some scripts depending on features chosen in FeatureTree. But is seems like installer execute all script which I added.
<Feature Id="FeatureProduct" Title="App Setup" Level="1" ConfigurableDirectory="INSTALLFOLDER">
<ComponentGroupRef Id="ComponentsProduct" />
<ComponentRef Id="ComponentMenuStart" />
<ComponentRef Id="ComponentDesktopFolder"/>
<ComponentRef Id='SqlComponent.DatabaseSchemeCreator' />
<Feature Id='NE051' Title='Module1' Description='Module 1' Level='1'>
<ComponentRef Id='ComponentModules.Module1' />
<ComponentGroupRef Id='ComponentGroupModul1' />
<ComponentRef Id='SqlComponent.DatabaseModule1' />
</Feature>
<Feature Id='NE041' Title='module2' Description='Module 2' Level='1'>
<ComponentRef Id='ComponentModules.Module2' />
<ComponentGroupRef Id='ComponentGroupModul2' />
</Feature>
</Feature>
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="SqlComponent.DatabaseSchemeCreator" Guid="2E7CB14E-7190-4C35-A83F-9B1A5C7A2923">
<Condition><![CDATA[AUTO_CONFIGURE_DB = 1]]></Condition>
<sql:SqlDatabase Id='SqlComponent.DatabaseSchemeCreator' Database='[PROP_SQL_DATABASE_NAME]' Server='[PROP_SQL_SERVER_NAME]'
CreateOnInstall='yes' ContinueOnError='no'>
<sql:SqlScript Id='SqlComponent.DatabaseSchemeCreator' BinaryKey='CreateTablesScript' ExecuteOnInstall='yes' />
</sql:SqlDatabase>
</Component>
</DirectoryRef>
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="SqlComponent.DatabaseModule1" Guid="B7E392C5-3A1E-4F73-9B86-54394E93330B">
<Condition><![CDATA[AUTO_CONFIGURE_DB = 1]]></Condition>
<sql:SqlDatabase Id='SqlComponent.DatabaseModule1' Database='[PROP_SQL_DATABASE_NAME]' Server='[PROP_SQL_SERVER_NAME]'
CreateOnInstall='yes' ContinueOnError='no'>
<sql:SqlScript Id='SqlComponent.DatabaseModule1' BinaryKey='Module1Script' ExecuteOnInstall='yes' />
</sql:SqlDatabase>
</Component>
</DirectoryRef>
Every time I don't mark module 1 in FeatureTree to install Wix execute a script for module 1. Condition in components work well. Do you have any ideas how to prevent this?
As far as I can see you didn't use any feature state for your components (or where does the AUTO_CONFIGURE_DB-property come from?).
If I understood you correctly you want those scripts to be executed only if the related Feature has been set to be installed. According to Conditional Statement Syntax you can use the &feature-action in your conditions:
For example, the conditional expression "&MyFeature=3" evaluates to True only if MyFeature is changing from its current state to the state of being installed on the local computer, INSTALLSTATE_LOCAL.
In your case this would probably translate to the following, e.g. execute the script only if the feature NE051 has been selected to be installed locally:
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="SqlComponent.DatabaseSchemeCreator" Guid="2E7CB14E-7190-4C35-A83F-9B1A5C7A2923">
<Condition><![CDATA[&NE051=3]]></Condition>
<sql:SqlDatabase Id='SqlComponent.DatabaseSchemeCreator' Database='[PROP_SQL_DATABASE_NAME]' Server='[PROP_SQL_SERVER_NAME]' CreateOnInstall='yes' ContinueOnError='no'>
<sql:SqlScript Id='SqlComponent.DatabaseSchemeCreator' BinaryKey='CreateTablesScript' ExecuteOnInstall='yes' />
</sql:SqlDatabase>
</Component>
</DirectoryRef>
</Fragment>