WiX Installer Bootstrapper - How to set a string variable based on a condition? - wix

I am using a Wix bootstrapper. I have a custom Theme that has a radio button that sets variables called "Client" or "Server", based on which button is selected.
What I'm searching for is a way to have the "InstallCommand" in an "ExePackage" be different based on whether "Client" or "Server" is set. (They are boolean "1" or "0") variables.
I could always duplicate the "ExePackage" and run the same installer executable with a different InstallCommand based on the variable. That has worked for me in the past. However, I am trying to avoid including the ExePackage twice, since it's rather large and would unnecessarily bloat the bootstrapper executable.
I was thinking of trying to set a variable or property based on whether one or the other is set, then use that variable or property in the InstallCommand. Any thoughts on how to go about doing this? I've searched and I can't find a solution.

My research has indicated that this simply cannot be done with the Wix managed bootstrapper application. You have to "roll your own" custom bootstrapper application to achieve this.

Related

Installing a binary if it is already present using WIX installer

Background : Customers have been copying a set of binaries and putting it on a specific location for them to run NinjaTrader Indicators. For Eg: lets assume The customer "A" has used First.dll, second.dll and Customer "B" has used First.dll and Third.dll (they did not use any installers, but just copied from a server location)
Current Requirement: I have to create a WIX installer with all possible updated DLLs with a caveat that it should install only those updated dll whose previous version customer has already on his machine. So if the new WIX installer has First_1000.dll, Second_1000.dll, Third_1000.dll and Fourth_1000.dll, then it should behave on Customer "A" and "B" as follows:
Customer "A": Uses this installer, his machine should have only First_1000.dll and Second_1000.dll and not others.
Customer "B": Uses this installer, his machine should have only First_1000.dll and Third_1000.dll and not others.
What I have Tried: Using the directorySearch and FileSearch, but I am not able to conditionally install, either it installs all or installs none. Other issue with this is it wont remove the previous version of the binary.
What I need: How to call a CustomAction method and use the return result to make decision to install or not, with this I can remove the previous version of the file as well.
Overall advice: don't approach deployment as a development task first and foremost. Get your files and settings deployed, and do any advanced configuration on application launch.
Do not implement any custom logic if all you need is a file copy and some registry keys - and certainly don't do it all in one custom action using WiX / MSI as a "shell" or "container" only.
There are many tools that can help you deploy your software: How to create windows installer (also lists legacy tools that are not MSI tools).
At one point I wrote this step-by-step answer for a WiX installer.
If you ask me for the easiest way to achieve what you want, then I would install all files via a single MSI and use the application itself to adjust any access to advanced features (if applicable) via the license code (if any). This minimizes your deployment complexity, and puts advanced features in a familiar context: application debugging in user context (most likely).
This avoids a world of pain of custom setup logic - which is very heavily overcomplicated by sequencing, impersonation and conditioningconcerns, not to mention runtime dependencies and other challenges. Collectively this causes the overall problem that setup logic is very hard to debug - due to the collective impact of all these aspects of complexity.
The general approach that should work is to:
Group the components (that contain one file each) into Features that when installed will do the right thing for each customer.
Use Feature conditions based on the results of the file searches and the property values set from the searches.
This example in the WiX docs, Conditional Installation seems to do almost exactly what you're looking for.
In the longer term you should build a setup that doesn't require this type of search behavior. You don't say why the file names change, but I'll guess that you are using the different names as a kind of version control. Installs, patches, service packs, upgrades and so on all replace files based on their binary versions. In a well-designed application and install, the binary versions of the existing files might all be 1.0. If the new files are all versioned 1.1 then all the old files will be replaced. If one was version 1.0 (and therefore unchanged) it would not be replaced. The file names would not change. Version control is the basis for updates, so I recommend moving in that direction.

Any side-effects to changing Wix Directory element Id value?

I've inherited a Wix-based installer. Most of the Directory#Id attributes are generated in the form Id="dirE039ABA27AC02A3F578F38F62EAD8474". Are there any side effects to changing that value in and every place the ID is referenced? I am hoping this isn't, for example, like a Component#Guid which must not be changed otherwise Windows Installer won't know its the same component.
Are all Wix #Id attributes similar? I'm hoping they are just internal Wix linkages and have no semantics for Windows Installer.
I want to change IDs from gibberish to something self-documenting.
Directory/#Id values end up in the .msi as specified.

wix burn custom bootstrapper - custom compiler extension

I have a custom bootstrapper using burn, in which I have to detect the driver version of a specific printer on startup and store this value in a burn variable for later usage. Until now, I did this in the overriden Run method of BootstrapperApplication, but I would rather create a WixExtension, to be able to do something like this:
<customUtil:PrinterDriverVersion PrinterName="somePrinter"
Variable="variableToStoreVersionValue" />
This would be similar to the RegistrySearch element in wix's UtilExtension.
There is an example of a CompilerExtension in the book "WiX 3.6: A Developer's Guide To Windows Installer XML", but I don't get it. Why do I need a new msi table? I just want to use that in burn, not in an msi installer?
I looked at the source code of wix, trying to understand, how the RegistrySearch element works. So UtilCompiler just parses the xml attributes and then creates some rows in the WixRegistrySearch table. This table gets iterated by the binder, who writes all searches in the BurnManifest and then creates the resulting output file (.exe). But when and where do this searches get executed at runtime?
Is a CompilerExtension capable to get my task done, or am I on the wrong way?
WiX doesn't have this functionality today. This use case is also needed for the VSExtension to support installing VSIX packages into VS2017 with a bundle, since code needs to be executed to detect VS2017 instances. I created a feature request here.
The UtilExtension searches are special. As you said, they end up in the BurnManifest. The code that executes the searches is in the Burn engine.

Wix generate single component id for entire tree

I am someone with little to no experience with wix and I am trying to support Windows also for the component I am responsible for. I am trying to create merge module for a set of files that my product generates. These files exist in numerous sub directories. I was wondering how I can create a single component ID for all the files in the entire tree. I am not worried about minor upgrades as that is something I am not going to be doing. I am trying to avoid generating numerous GUIDs for each of the file.
Also is there any way I can change the name of the root directory I want the files to be installed. Currently, in our build system the files I want to install end up in a directory name "install". In the wxs file generated by heat it comes up as install. I was wondering if I could change it to the actual product name instead of "install".
Use one file per component - this avoids all sorts of problems (except .NET assemblies spanning multiple files). See the following thread: One file per component or several files per component?
Wix is a great framework for creating installers, but it has a steep learning curve. I strongly recommend you read a few sections of this great, online tutorial: https://www.firegiant.com/wix/tutorial/
If you are a "sample based tinkerer", you can find an even quicker, sample based tour in this article: http://www.codeproject.com/Tips/105638/A-quick-introduction-Create-an-MSI-installer-with
Wix is hands-on. Just focus on the samples, and focus on getting the components created and a major upgrade set up:
How to implement WiX installer upgrade? (modern, convenience way)
How to get WiX major upgrade working? (legacy way - more flexible, less convenient)
http://wixtoolset.org/documentation/manual/v3/howtos/updates/major_upgrade.html
Once you got that running the rest of the details fall into place by reading the documentation for whatever feature you need. Using Visual Studio / Votive with intellisense ensures that you can learn as you go with features such as shortcuts, ini files, xml files, dialogs, etc...
Another top tip is to use dark.exe (part of the Wix toolkit) to decompile existing MSI files. This yields Wix XML with code you can copy and paste into your own Wix files. I use other MSI tools to compile such MSI files, and then copy the sections I need into my Wix file - just to speed up the process of creating the Wix XML. Studying the decompiled XML is very educational - a real time saver.
UPDATE, May 2021: Some more links:
WiX Quick Start - Very long version
WiX Quick Start - Short version
If all the files are going to the same destination folder, then you can create one single COMPONENT with all the FILE within it. There is nothing stopping you to do that. You can then just create one GUID for that component. Also read these answers which talks about the advantages vs disadvantages of one component vs multiple components before you implement it: Answer1 Answer2. To Summarize:
You will have trouble with minor upgrades/repairs. If a component is
being updated, only the file designated as the KEYPATH is checked to see if
it is out of date: if it is up to date, all the others are ignored.
You'll also have difficulty if you want to add or remove files from each
component. Once released, a component is immutable (in terms of what files
are in it). The only way to update it without breaking component rules would
be to effectively remove and install the a new version of the MSI.
Understanding the component rules is key in Windows Installer and one file
per component makes the component rules easier to work with, which is why it
is the recommendation of many people here.
LINK
The root directory name can be changed by modifying the "Name" property for the DIRECTORY element.

MSI Properties Empty on Passive, Basic UI, and No UI Install

I am working on an installer with a handful of custom actions that look for values in the following MSI properties:
ADDLOCAL
ADDDEFAULT
REINSTALL
REMOVE
When running the installer with the full UI, these properties contain lists of comma-separated feature names as appropriate given the options that are selected by the user. However, when I run the installer in passive mode or with only a basic UI (or no UI) from the command line, I find that the properties are empty/blank. It is only when I explicitly set them from the command line that they have any value. This is an acceptable work-around, but it would be much better if these could take on some kind of default, such as "all", without requiring values to be passed on the command line. Is there some way I can specify this in WiX (which I am using to build the MSI) or do I have to do something in the custom action code (or something else entirely)?
I have looked at the property reference here, but I did not see any mention of how one could specify default features for these properties.
What I also found interesting is if I do specify a feature this way on the command line during install, it seems to be stored for the uninstall in the REMOVE property (in other words, I do not have to pass any parameters when uninstalling in any mode). Is this a feature that I can rely on? Will it automatically update if someone modifies the installation later?
I'm running WiX 3.5.2519 and using Visual Studio 2010 with Visual C++ for the custom action code. Thanks for any help you can give me!
Edit:
Actually, I was wrong. It appears that the REMOVE property is always set to "all" when uninstalling and running in one of these modes, even if I pass a different value on the command line or only install a subset of features. This seems broken. Am I doing something wrong here?
C:\> msiexec REMOVE=FeatureName /passive /l* uninstall.log /x Product.msi
It will completely ignore what I specify for "FeatureName" and use "all" in its place.
Your custom actions probably shouldn't examine those properties. Instead they should examine the feature and/or component states of the product, depending on what they're trying to do. In conditional statement syntax, this looks like $component-action or &feature-action (where you use the name of the component or feature whose action you are trying to condition against). In C++ (for inside the custom action) this looks like MsiGetFeatureState or MsiGetComponentState, and these are of course made available through similar means in most other languages (such as session.FeatureRequestState / session.ComponentRequestState in a language you shouldn't use).
It is a recommended practice that all properties to be used by the installation be entered into the Property table with an initial value. The installer sets the properties to these values at the launch of the installation. Properties for which a blank is an acceptable value and properties built into the installer do not need to be initialized.
You can then change the default value programmatically or on the command line as described here: Using Properties.