How to deploy 64-bit and a 32-bit Windows Installer package as a single setup? - wix

I need to deploy a software setup targeting both, Windows 64bit and 32bit. I have two separate Windows Installer databases (created with WiX) for each platform, and I am using dotNetInstaller to combine both into a single installation bootstrapper executable.
I'm currently using version 1.10 of dotNetInstaller and set auto_close_if_installed=True, because I want to comletely hide the bootstrapper from the user. Still, dotNetInstaller insists on displaying a sill progress bar window while my installer is running, and doesn't really auto-close. The user needs to confirm a dialog box telling him that the application was successfully installed. But the real deal-breaker is that it doesn't support Windows 8 (yet).
Upgrading to a later version of dotNetInstaller seems to break auto_close_if_installed, so it's even worse.
So my question is: what is the current state of the art to deploy both setups in a single executable. Would Wix Burn be an option?
I know that in an ideal world, I simply provide my customers with separate installers for either platform. But they happen to be completely unaware of such subtleties, most of them don't even know what platform they are using.

I would definitely use Burn in this scenario. Something akin to the following:
<Wix>
<Bundle...>
<BootstrapperApplicationRef Id='WixStandardBootstrapperApplication.HyperlinkLicense' />
<Chain>
<MsiPackage InstallCondition='NOT VersionNT64' SourceFile='path\to\x86.msi' />
<MsiPackage InstallCondition='VersionNT64' SourceFile='path\to\x64.msi' />
</Chain>
</Bundle>
</Wix>
This is exactly one of the scenarios Burn was designed to handle.

You can do it in a single Wix via Conditions and Features.
<Feature Id='X86' Level='1'>
<ComponentRef Id='X86Feature1' />
<Condition Level="1">NOT VersionNT64</Condition>
</Feature>

Related

Implement dependency of ExePackage on other MSI so uninstall completes if required MSI was already removed

Background:
I have a large project which consists of a server component, client component and microservice hosting component. Each is packed in its own MSI.
The server component and the microservice hosting component each install a Windows service.
The server components' Windows service depends on the microservice hosting components' Windows service.
Everything is chained together and distributed by a setup bundle *.exe installer. In the installer, a customer can choose if he wants to install only the client, only the server or both (client and server).
At the end of the installation the customer is informed that everything went well (all files copied, all services running) (= success message) or not (= failure message with the possibility to send the log files to our help desk).
Updates are implemented as MajorUpgrades since the setup consists of hundreds of files. Our customers expect that if an update fails, the setup "rolls back" to the previously installed version of the product (= the whole bundle).
What lead to the problem?
Since Wix v3 does not handle rollbacks of bundles the way I expect it (see here) -- only the MSI that triggered the failure is rollbacked, previously installed MSIs in the chain before are only removed -- we had to implement a few workarounds:
install the component, which most likely causes errors on a customer machine, first -- then install the other MSIs.
deal with the Windows service dependencies of the components later (= restart the server component service)
Point 2 is achieved by using ExePackages that start and stop the servers' Windows service. This is done by using the technique described here. The service component MSI does not start the Windows service, only stops it on uninstall.
For architectural reasons, I do not want to configure the service components' Windows service in the microservice hosting service MSI.
This lead to the following Wix source code:
Bundle.wxs
<Chain>
            <PackageGroupRef Id="SqlExpress"/>
            <PackageGroupRef Id="vcredist"/>
            <!-- ... -->
            <PackageGroupRef Id="ServiceHandlingStop" />
            <PackageGroupRef Id="Server"/>
            <PackageGroupRef Id="MicroServiceHost"/>
            <PackageGroupRef Id="ServiceHandlingStart" />
            <PackageGroupRef Id="Client"/>
        </Chain>
Fragment of the "service handling":
The decision of the user what to install is stored inside "InternalInstallType"
<Fragment>
<PackageGroup Id="ServiceHandlingStop">
<ExePackage Id="ServiceHandlingStopCall"
Compressed="yes"
DisplayName="Service Management"
SourceFile="redist\Runner.bat"
InstallCommand="net stop WCFHostService"
UninstallCommand="net start WCFHostService"
DetectCondition="WixBundleInstalled = 1 AND InternalInstallType <> "Client""
InstallCondition="InternalInstallType <> "Client""
Permanent="no"
Vital="no"
PerMachine="yes">
<ExitCode Behavior="success" />
</ExePackage>
</PackageGroup>
<PackageGroup Id="ServiceHandlingStart">
<ExePackage Id="ServiceHandlingStartCall"
Compressed="yes"
DisplayName="Service Management"
SourceFile="redist\Runner.bat"
InstallCommand="net start WCFHostService"
UninstallCommand="net stop WCFHostService"
DetectCondition="WixBundleInstalled = 1 AND InternalInstallType <> "Client""
InstallCondition="InternalInstallType <> "Client""
Permanent="no"
Vital="yes"
PerMachine="yes">
<ExitCode Value="0" Behavior="success" />
<ExitCode Behavior="error" />
</ExePackage>
</PackageGroup>
</Fragment>
What should be achieved by this bunch of code?
"Only if the server component is installed, start the server components' Windows service after the microservice hosting component is installed. On a failed upgrade, start the server components' Windows service after the previous version was installed again. If the user chooses to uninstall, don't care about the server components' Windows service."
The problem
If the setup bundle on uninstallation by a user is killed / closed unexpectedly, it can occur that some of the MSIs mentioned in the chain above are already installed.
Now if the user launches the setup again to uninstall once more, Burn runs the ExePackage ServiceHandlingStartCall again and since is marked as Vital=yes (to inform the user if the service startup succeeded on install, upgrade and rollback and abort if neccessary), the setup fails and the user is unable to remove the product.
Question:
How to implement the dependency between the ExePackage ServiceHandlingStartCall and the service component MSI so uninstallation is possible even though the other MSIs are already gone?
I tried
"InstallCondition" / "DetectCondition"
Dependency I don't find any examples / documentation
Or if someone has an idea of how to handle the dependency of server component and microservice hosting component, my ears are wide open.
Thank you!
Are you able to check whether the individual compoments (MSIs) are installed?
It seems you're only checking if the entire bundle is installed or not (WixBundleInstalled = 1). Even though the InternalInstallType variable holds the "decision of the user what to install", that might not reflect the actual state of the system if the installer was previously interrupted, as you're describing.
If you could make every component (MSI) mark if it is installed or not (in the registry, for example) you could then do a RegistrySearch in Wix and only try to uninstall the component if it was detected.
I've implemented the same thing recently. This code check if the WebView2 Runtime is already installed, before attempting to install it:
Bundle.wxs (Bootstrapper)
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle ...>
... code removed for brevity
<!-- Check if WebView2 Runtime already installed -->
<util:RegistrySearch
Root="HKLM"
Key="SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"
Value="pv"
Variable="WV2RuntimeMachineVersion" />
<util:RegistrySearch
Root="HKCU"
Key="SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"
Value="pv"
Variable="WV2RuntimeUserVersion" />
<Chain>
<!--This will only be installed when INSTALLING or REPAIRING and the WebView2 Runtime is not already installed-->
<ExePackage Id="TheWebView2Runtime"
DisplayName="WebView2 Runtime"
Vital="no"
Cache="no"
Permanent="yes"
SourceFile="..\..\data\bundle\MicrosoftEdgeWebView2RuntimeInstallerX64.exe"
InstallCommand="/silent /install"
DetectCondition="NOT (WixBundleAction = 5 OR WixBundleAction = 7) OR (WV2RuntimeMachineVersion >= v102.0.1245.22 OR WV2RuntimeUserVersion >= v102.0.1245.22)" />
</Chain>
</Bundle>
</Wix>
Note that in my case, I don't want to uninstall the dependency (WebView2 Runtime) ever, but that could easily be changed by removing the NOT (WixBundleAction = 5 OR WixBundleAction = 7) of the DetectCondition.
Do you think this approach might work for you?

Wix ExePackage Side by Side Install without Uninstall

I have two products which I'm trying to write an installer for. Both products are wix bundles which both have a third product bundle as a requirement.
Ideally what I want to happen when you install one is:
If Product3 is not installed then it should be.
If Product3 is installed and installed version is higher or the same do nothing.
If Product3 is installed and installed version is lower then upgrade.
If uninstalling and product1 or 2 is still installed do not uninstall product3.
So far I was able to conquer some of these points but not all at the same time.
Originally I tried getting the installed version using a ProductSearch and using InstallCommand. However I ran into problems with uninstalling when doing side by side installs because the installcommand is more like "requested install state" and so if I don't want it to install when it detects the same version it actually starts uninstalling it.
I took a look at this similar answer:
How to avoid uninstalling previously installed ExePackage (redistributables) while installing a WiX Bundle?
which suggested using the provideskey and requires elements but I cannot find any useful documentation on them whatsoever. I tried experimenting with it but it doesn't seem to do anything at all.
I've looked at RelatedBundle but I'm not sure it's what I'm after. Seems more targeted at hotfixing systems.
I was hoping there was a way of doing this without having to resort to custom actions since that seems a bit extreme for what seems to be rather simple functionality.
After a lot of trial and error I figured out how to get the DependencyExtension working.
In the example below ProductC is a Wix Bundle executable. This bundle includes an MSI file. I use a productSearch to look for the upgrade code of that MSI file (NOT THE BUNDLE) to detect if it's already installed.
In your bundle file for project A and B:
<Wix xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle>
<util:ProductSearch Id="ProductCInstallSearch"
UpgradeCode="{ProductC_MSI_UpgradeCode_GUID}"
Variable="ProductCInstalled"
Result="state"/>
<dep:Requires Id="ProductCRequired" ProviderKey="ProductC"/>
<Chain>
<PackageGroupRef Id="ProductC_pkg"/>
</Chain>
</Bundle>
<Fragment Id="Required_Pkgs">
<PackageGroup Id="ProductC_Pkg">
<ExePackage Id="ProductC_Bundle"
Permanent="no"
DetectCondition="NOT ProductCInstalled = 2"
InstallCommand="/quiet"
UninstallCommand="/uninstall /quiet">
<dep:Provides Key="ProductC"
Version="0.0.0.0">
<dep:RequiresRef Id="ProductCRequired"/>
</dep:Provides>
</ExePackage>
</PackageGroup>
</Fragment>
</Wix>
Now you can install A and B in any arrangement and when uninstalling product C will only be removed when the last one is uninstalled.

How to bundle 6 msi into one msi installer

I have 6 msi that I want to bundle into single msi package. These 6 are office addin, out of these 3 are for office 2003 and 3 for office 2007. So my single msi should install only 3 addon based on the version of office. And there are some prerequisites that i want to install before these msi.
I tried using wix for once it created a setup but after sometime same project gave error: "Error 1 Unresolved reference to symbol 'ChainPackageGroup:wwwwww' in section 'Bundle:wixB2'" .
Setup creted by wix was able to install the setups but was not able to uninstall them, may be uninstallation needed admin rights but i was not able to give.
I also tried dotnetinstaller but i could not find how to add launch condition for my 6 installers. (Inatllcheck in dotnetinstaller only checks existense of the product getting install not the launch condition) If anybody can tell me how to add launch condition like if office 2007 present then install else do not, I will be able to complete my project if somebody help me to add launch condition.
So can you please tell me what should I do to create a single installer?
I Am also new to Wix. If You post your code It will be Helpful to solve your problem. You can go through following approach it might help you.
Considering user have office 2007 installed on his system your installer should install only Add-Ins for 2007. and as you have executables for add-ins Bootstrapper is best approach for it.
For Conditional installation you first need to find which version of office is already installed.
This you can do using Registry Search
<util:RegistrySearch Id ="Office2007" Root="HKLM" Key="SOFTWARE\Microsoft\Office\12.0\Word\InstallRoot::Path"/>
This will search in specific path.
Now for Installation
<ExePackage Id="2007Addin" SourceFile="your addin path"
InstallCondition="(Office2007)"/>
There are many other useful arguments also. go through them.
Sample Program
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="WordAddin" Version="1.0.0.0" Manufacturer="NSS" UpgradeCode="51d04319-a135-487c-a4bb-aed77417bda7">
<BootstrapperApplicationRefId="WixStandardBootstrapperApplication.RtfLicense" />
<util:RegistrySearchRef Id ='Office2007'/>
<--Here Install condition parameter checks if specific key is found if found installs packege -->
<--You can use NOT Office2007found this will install only if registry key not found-->
<Chain>
<MsiPackage Id ="officeAddin" Compressed='yes' Cache='yes' Name='office addin' SourceFile='officeadd.msi' InstallCondition='Office2007found' DisplayInternalUI='yes'/>
</Chain>
</Bundle>
<!--Registry Search to find Which Office Version Is installed (incase registry search failed change keys according)-->
<Fragment>
<util:RegistrySearch Id="office2007" Root="HKLM" Key="SOFTWARE\Microsoft\Office\12.0" Value="Version" Variable="Office2007found"/>
<--Below condition is only to check whether registry search is successful or not. remove it if not required-->
<bal:Condition Message="Failed to search regKey">Office2007found</bal:Condition>
</Fragment>
</Wix>
For Your Reference
wix installer 3.7 bootstrapper Registry search
How to detect installed version of MS-Office?
http://www.c-sharpcorner.com/UploadFile/cb88b2/installing-prerequisites-using-wix-bootstrapper-project-and/
Launch Condition to Detect Office 2010 Applications

Installer with WiX (pre-installed by Admin and Updated by User)?

We've created an installer using WiX.
In the registry we save it under HKCU (see example).
Desktop Icons and everything is installed for the Current User.
<DirectoryRef Id="INSTALLDIR">
<Component Id="CMP_SaveInstallDir" Guid="52e5e617-2c9a-4514-a6b0-055e4adc6a0b">
<RegistryValue Id="MyInstallDirId" KeyPath="yes" Action="write" Root="HKCU" Key="Software\ABC\MyProduct" Name="MyProduct" Value="[INSTALLDIR]" Type="string" />
</Component>
</DirectoryRef>
For upgrades we also use WiX. We try find the registry key and if it is available we install the upgrade.
That works well, if the person who installed the full installer installs the upgrade installer.
Now the installer should also be used to pre-install the software on some computers. That means, an Admin user ("Joe Admin") installs the software.
Later on a normal user ("Pete User", with the right to install software) should be able to install an upgrade.
But as the full install was done by "Joe Admin", "Pete User" can't upgrade with an upgrade installer as the registry key can't be found in his registry (HKCU of "Pete User").
I think that this scenario isn't unusual and so I hope someone can help me to find a solution.
Thanks in advance!
Here is an article which may help you: http://setupanddeployment.com/installation-environment/peruser-permachine/
Basically, you are handling the install locations incorrectly. If your installation is per-machine (for all users), it should use only per-machine locations. HKEY_CURRENT_USER is a per-user location and using it in a per-machine installer is a bad practice. Hence your problem.
I think Cosmin is right and you have to use per-machine installation in this case.
After all, if Joe Admin installed the application, then only this user has access to it: the desktop icons, program files and its settings are stored in the admin profile. Therefore Pete User has no access to any components of the application.
So either you make the installation per-machine or allow users to install it (not only upgrade).

Bundling Apple's Windows Bonjour installer into our msi

I've been asked to bundle Apple's Bonjour installer into our own msi installer, so that Bonjour automatically gets installed alongside our software. Anyone done this before? It doesn't seem to be trivial, as an msi installer cannot include and kick off another one. I assume I'd need some kind of batch file to run the two installers sequentially?
You'll need to use a bootstrapper to chain the Bonjour install with your installer. If you are using WiX 3.6 or later, using Burn to create a package bundle is a good option.
I found the Bonjour installer by downloading the Bonjour SDK and opening it in 7-zip, though I'm sure installing the SDK would provide access to it as well.
The way I typically like to do this is to add a new source file to your setup project for each dependency package to keep that logic separate from the main application setup.
The Bonjour package can be listed as a remote payload to retrieve on the fly, or build it into your setup. In this case, it seems more likely to build it in (Compressed="yes"). If you need to add any extra dependencies related to bonjour or parameters to pass into it, you could define them here as well.
<Fragment>
<!-- if a web link actually exists, I didn't find it... -->
<?define BonjourWebLink = "http://path/to/Bonjour.msi"?>
<PackageGroup Id="BonjourWeb">
<MsiPackage Id="BonjourWeb"
Compressed="no"
DownloadUrl="$(var.BonjourWebLink)">
</MsiPackage>
</PackageGroup>
<PackageGroup Id="Bonjour">
<MsiPackage Id="Bonjour"
Compressed="yes"
SourceFile="path\to\Bonjour.msi"/>
</PackageGroup>
</Fragment>
In your main bundle you just need to add a reference to the correct package group.
<Chain>
<PackageGroupRef Id="Bonjour"/>
<MsiPackage SourceFile="path\to\YourProduct.msi"/>
</Chain>
Since Bonjour uses MSI instead of an executable, you don't need to do anything to detect whether it is present or not; Burn will handle that for you. Actually, since WiX harvests most of the information your bundle needs from the MSI, this might be overkill, and you could just put in the MsiPackage element in your chain directly.
Don't forget to carefully check Apple's terms for doing this.
This would be a bit more work, and is prone to issues with upgrading, but you can take the Bonjour MSI and decompile it using dark. Convert the decompiled MSI into a Merge module that can be included with your installer, and you will have a single install. I have done this with some driver installs in the past, and it is usually not that complicated.
You need a bootstrapper; there are several freely available out there, including one being developed in WiX called Burn.
Wix Burn is relatively stable now.I`m using Wix 3.8.
If you are allowed to redistribute Bonjour Installer,you can chain the installer in Wix Burn. You can even put a condition to specify Bonjour as prerequesite for your installer.If it is not present,then Bonjour will be deployed, else it can be skipped.
You can check this link for understanding Burn.
http://wixtoolset.org/documentation/manual/v3/bundle/