Custom WiX Managed Bootstrapper Application
by bryanpjohnston
I put together a sample project to show the minimum code needed to create your own managed bootstrapper application using WiX. I wrote it in C# using the MVVM pattern. This is indeed a bare bones example and if you are serious about writing your own managed bootstrapper application, you should download the WiX 3.6 source code and follow their example (see src\Setup\WixBA).
My solution contains three projects (can download the full source here).
- TestBA: The bootstrapper UX.
- BootstrapperSetup: The main bootstrapper executable that lists the packages to be installed.
- DummyInstaller: A dummy .msi that gets installed by the bootstrapper.
TestBA
My managed bootstrapper application is called TestBA and it is written in C# and follows the MVVM pattern. To keep the code I had to write to a minimum, I used the MVVM Light Toolkit (http://mvvmlight.codeplex.com/).
Note the following references used by this project:
- BootstrapperCore.dll (included with the WiX SDK)
- Microsoft.Deployment.WindowsInstaller.dll (included with the WiX SDK)
- WindowsBase.dll (for threading)
Let’s examine each file that makes up my bootstrapper application.
AssemblyInfo.cs
The important part about is to identify that this class is a bootstrapper application like so:
using Microsoft.Tools.WindowsInstallerXml.Bootstrapper;
[assembly: BootstrapperApplication(typeof(Examples.Bootstrapper.TestBA))]
BootstrapperCore.config
The is the config file that accompanies your managed bootstrapper application. The important part is that the assembly name match the name of your bootstrapper application. See below assemblyName=”TestBA”. For more information, read this blog post by Heath Stewart.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="wix.bootstrapper" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperSectionGroup, BootstrapperCore"> <section name="host" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.HostSection, BootstrapperCore" /> </sectionGroup> </configSections> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" /> </startup> <wix.bootstrapper> <host assemblyName="TestBA"> <supportedFramework version="v4\Full" /> <supportedFramework version="v4\Client" /> </host> </wix.bootstrapper> </configuration>
TestBA.cs
This is the class that actually implements the BootstrapperApplication class. I create my ViewModel, View and set the View’s DataContext, then show the UI.
using System.Windows.Threading; using Microsoft.Tools.WindowsInstallerXml.Bootstrapper; namespace Examples.Bootstrapper { public class TestBA : BootstrapperApplication { // global dispatcher static public Dispatcher BootstrapperDispatcher { get; private set; } // entry point for our custom UI protected override void Run() { this.Engine.Log(LogLevel.Verbose, "Launching custom TestBA UX"); BootstrapperDispatcher = Dispatcher.CurrentDispatcher; MainViewModel viewModel = new MainViewModel(this); viewModel.Bootstrapper.Engine.Detect(); MainView view = new MainView(); view.DataContext = viewModel; view.Closed += (sender, e) => BootstrapperDispatcher.InvokeShutdown(); view.Show(); Dispatcher.Run(); this.Engine.Quit(0); } } }
MainView.xaml
My view is nothing special. I have three buttons that are bound to commands for Install, Uninstall and Exit. I also include a little rotating circle that appears when the bootstrapper is installing or uninstalling. If you look at the WiX source code itself, you can see a good example at how to implement a progress bar to track installation progress.
<Window x:Class="Examples.Bootstrapper.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="My Ugly Bootstrapper Application" Width="400" MinWidth="400" Height="300" MinHeight="300"> <Window.Resources> <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> </Window.Resources> <Grid> <TextBlock Text="Welcome to my test bootstrapper application." Margin="10" FontSize="18" HorizontalAlignment="Center" Foreground="Red" VerticalAlignment="Top" /> <Ellipse Height="100" Width="100" HorizontalAlignment="Center" VerticalAlignment="Center" StrokeThickness="6" Margin="10" Visibility="{Binding Path=IsThinking, Converter={StaticResource BooleanToVisibilityConverter}}"> <Ellipse.Stroke> <LinearGradientBrush> <GradientStop Color="Red" Offset="0.0"/> <GradientStop Color="White" Offset="0.9"/> </LinearGradientBrush> </Ellipse.Stroke> <Ellipse.RenderTransform> <RotateTransform x:Name="Rotator" CenterX="50" CenterY="50" Angle="0"/> </Ellipse.RenderTransform> <Ellipse.Triggers> <EventTrigger RoutedEvent="Ellipse.Loaded"> <BeginStoryboard> <Storyboard TargetName="Rotator" TargetProperty="Angle"> <DoubleAnimation By="360" Duration="0:0:2" RepeatBehavior="Forever" /> </Storyboard> </BeginStoryboard> </EventTrigger> </Ellipse.Triggers> </Ellipse> <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Right"> <Button Content="Install" Command="{Binding Path=InstallCommand}" Visibility="{Binding Path=InstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="10" Height="20" Width="80"/> <Button Content="Uninstall" Command="{Binding Path=UninstallCommand}" Visibility="{Binding Path=UninstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="10" Height="20" Width="80"/> <Button Content="Exit" Command="{Binding Path=ExitCommand}" Margin="10" Height="20" Width="80" /> </StackPanel> </Grid> </Window>
MainViewModel.cs
This is my ViewModel obviously. In the constructor I pass in the bootstrapper engine, which I like to think of as my Model. That may or may not be incorrect, but that’s how it makes sense in my head. You can also see in the constructor that I subscribe to three events.
The DetectPackageComplete event gets fired after Burn checks whether or not a package in the chain is installed on the machine, so this is where we decide whether or not we want to show the Install or Uninstall button.
The PlanComplete event is fired when we are done planning the install (or uninstall) and this is where we instruct Burn to go ahead and proceed with the installation (or uninstallation).
The ApplyComplete event is fired when the installation/uninstallation is complete, so we can hide the install/uninstall buttons and the spinny circle.
using Microsoft.Tools.WindowsInstallerXml.Bootstrapper; using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; namespace Examples.Bootstrapper { public class MainViewModel : ViewModelBase { //constructor public MainViewModel(BootstrapperApplication bootstrapper) { this.IsThinking = false; this.Bootstrapper = bootstrapper; this.Bootstrapper.ApplyComplete += this.OnApplyComplete; this.Bootstrapper.DetectPackageComplete += this.OnDetectPackageComplete; this.Bootstrapper.PlanComplete += this.OnPlanComplete; } #region Properties private bool installEnabled; public bool InstallEnabled { get { return installEnabled; } set { installEnabled = value; RaisePropertyChanged("InstallEnabled"); } } private bool uninstallEnabled; public bool UninstallEnabled { get { return uninstallEnabled; } set { uninstallEnabled = value; RaisePropertyChanged("UninstallEnabled"); } } private bool isThinking; public bool IsThinking { get { return isThinking; } set { isThinking = value; RaisePropertyChanged("IsThinking"); } } public BootstrapperApplication Bootstrapper { get; private set; } #endregion //Properties #region Methods private void InstallExecute() { IsThinking = true; Bootstrapper.Engine.Plan(LaunchAction.Install); } private void UninstallExecute() { IsThinking = true; Bootstrapper.Engine.Plan(LaunchAction.Uninstall); } private void ExitExecute() { TestBA.BootstrapperDispatcher.InvokeShutdown(); } /// <summary> /// Method that gets invoked when the Bootstrapper ApplyComplete event is fired. /// This is called after a bundle installation has completed. Make sure we updated the view. /// </summary> private void OnApplyComplete(object sender, ApplyCompleteEventArgs e) { IsThinking = false; InstallEnabled = false; UninstallEnabled = false; } /// <summary> /// Method that gets invoked when the Bootstrapper DetectPackageComplete event is fired. /// Checks the PackageId and sets the installation scenario. The PackageId is the ID /// specified in one of the package elements (msipackage, exepackage, msppackage, /// msupackage) in the WiX bundle. /// </summary> private void OnDetectPackageComplete(object sender, DetectPackageCompleteEventArgs e) { if (e.PackageId == "DummyInstallationPackageId") { if (e.State == PackageState.Absent) InstallEnabled = true; else if (e.State == PackageState.Present) UninstallEnabled = true; } } /// <summary> /// Method that gets invoked when the Bootstrapper PlanComplete event is fired. /// If the planning was successful, it instructs the Bootstrapper Engine to /// install the packages. /// </summary> private void OnPlanComplete(object sender, PlanCompleteEventArgs e) { if (e.Status >= 0) Bootstrapper.Engine.Apply(System.IntPtr.Zero); } #endregion //Methods #region RelayCommands private RelayCommand installCommand; public RelayCommand InstallCommand { get { if (installCommand == null) installCommand = new RelayCommand(() => InstallExecute(), () => InstallEnabled == true); return installCommand; } } private RelayCommand uninstallCommand; public RelayCommand UninstallCommand { get { if (uninstallCommand == null) uninstallCommand = new RelayCommand(() => UninstallExecute(), () => UninstallEnabled == true); return uninstallCommand; } } private RelayCommand exitCommand; public RelayCommand ExitCommand { get { if (exitCommand == null) exitCommand = new RelayCommand(() => ExitExecute()); return exitCommand; } } #endregion //RelayCommands } }
BootstrapperSetup
This is the bootstrapper project that specifies which packages to install, and tells Burn to use the TestBA UX. Notice we need the reference to the WiX BalExtension. The BootstrapperApplicationRef must be “ManagedBootstrapperApplicationHost”. Also, notice the payloads for my bootstrapper application. We need to make sure the following gets included with the bootstrapper:
- TestBA.dll
- BootstrapperCore.config
- Microsoft.Deployment.WindowsInstaller.dll
- GalaSoft.MvvmLight.WPF4.dll (this is only because my TestBA.dll relies on the MVVM Light Toolkit)
Below, the DummyInstaller.msi is the package that I want to install.
Please also note the fragment at the bottom. Since our bootstrapper UX was written in .NET, we need to make sure .NET is installed. The WiX variable WixMbaPrereqPackageId specifies which package is required by our MBA. For more information, read this blog post by Heath Stewart.
<?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="My Test Application" Version="1.0.0.0" Manufacturer="Bryan" UpgradeCode="PUT-GUID-HERE"> <BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost"> <Payload SourceFile="..\TestBA\BootstrapperCore.config"/> <Payload SourceFile="..\TestBA\bin\Release\TestBA.dll"/> <Payload SourceFile="..\TestBA\bin\Release\GalaSoft.MvvmLight.WPF4.dll"/> <Payload SourceFile="C:\Program Files\WiX Toolset v3.6\SDK\Microsoft.Deployment.WindowsInstaller.dll"/> </BootstrapperApplicationRef> <Chain> <PackageGroupRef Id='Netfx4Full' /> <MsiPackage SourceFile="..\DummyInstaller\bin\Release\DummyInstaller.msi" Id="DummyInstallationPackageId" Cache="yes" Visible="no"/> </Chain> </Bundle> <Fragment> <!-- Managed bootstrapper requires .NET as a dependency, since it was written in .NET. WiX provides a Bootstrapper for the bootstrapper. The fragment below includes .NET. For more information or examples see Heath Stewart's blog or the WiX source: http://blogs.msdn.com/b/heaths/archive/2011/10/28/introducing-managed-bootstrapper-applications.aspx --> <WixVariable Id="WixMbaPrereqPackageId" Value="Netfx4Full" /> <WixVariable Id="WixMbaPrereqLicenseUrl" Value="NetfxLicense.rtf" /> <util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full" Value="Version" Variable="Netfx4FullVersion" /> <util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full" Value="Version" Variable="Netfx4x64FullVersion" Win64="yes" /> <PackageGroup Id="Netfx4Full"> <ExePackage Id="Netfx4Full" Cache="no" Compressed="yes" PerMachine="yes" Permanent="yes" Vital="yes" SourceFile="C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages\DotNetFX40\dotNetFx40_Full_x86_x64.exe" DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=164193" DetectCondition="Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)" /> </PackageGroup> </Fragment> </Wix>
Hope this makes sense.
Thank you! It`s really great! It`s saving my time!
This helped much, but does a MBA code needs to be this complex always ; like you used these events.
OnApplyComplete;
OnDetectPackageComplete;
OnPlanComplete;
It seems that you followed the same style of coding as WixBA. I m sorry if my comments sound vague, since I am new to C#, delegates and now you have included MVVM hence I am scratching my head “isn’t there something simple?”
Hey im new in wix….i also have two MSIs and I want to make a Burn UI which gives user the choice to select which MSI to install/uninstall (via checkboxes). as like ur queations..bt my question is wot get checkbox value in variable….
Awesome and very appreciated
I am now using a code similar to this patter.
I have two MSIs and I want to make a Burn UI which gives user the choice to select which MSI to install/uninstall (via checkboxes).
I plan to implement choice functionality using attribute in . But when I test my bundle , install is happening fine BUT uninstall says
– Will not uninstall package: MSI2.msi, found dependents: 1
– Found dependent: {08e74372-83f2-4594-833b-e924b418b360}, name: My Test Application
In what way can I tweak my code so that Burn can freely uninstall any of the MSI which was installed earlier.
Maybe your registry is messed up from testing. See my response to your SO question here:
http://stackoverflow.com/questions/12828514/wix-burn-issue-uninstall-fails-saying-found-dependent/12923606#12923606
What did you install to get the bootstrap packages located at: C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages\DotNetFX40?
I’ve been searching and can’t find anything. I also have the Platform SDK but I don’t see it there either.
Thanks!
I think I just downloaded it from here: http://www.microsoft.com/en-us/download/details.aspx?id=17718 then just copied it to that location.
Oh…that’s what I did! 🙂 I thought there was some SDK or something that included all of the .NET framework versions.
Thanks!!
I need to install .net 3.5 as a part of prerequisite from the Wix bootstrapper and i have developed Wix bootstrapper and msi file . Bootstrapper will check the Detectcondition and downloads/installs .net 3.5. But i needed to show a dialog/message box to the user before installing/download .net 3.5 from the Wix bootstrapper .Once the user click OK we will proceed with installation of .net. May i know whether it is possible do using bootstrapper ? I checked the code under src\Setup\WixBA and couldnt find a event handler for the same.
If you are using the standard bootstrapper application, you may be able to create a custom theme (not sure though, haven’t played with themes and the standard ba). However if you are talking about a custom managed bootstrapper application, then you would need to install .NET in order to run your installer, in which case .NET gets installed by a native bootstrapper and in my experience, you get prompted before it installs.
Thanks for the reply. I wanted messagebox which informs the user that .NET 3.5 is installed on the machine and once presses OK then only it should starting downloading /install the .net framework. For downloading i am using Payload element. I have the added the code inside OnDetectPackageComplete event by checking whether PackageId is Netfx4Full and correspondingly checking the Packagestate.
if (e.PackageId == “Netfx4Full”)
{
if(e.State ==PackageState.Absent)
MessageBox.Show(“.NET Framework 3.5 must be installed prior to installation of this product.”);
}
Is there any better way of doing this???
One more query if i double click on the bootstrapper setup application you have shared ,on a machine which doesnt have any .net installed will it work since
TESTBA is a .net application ??
Regarding your second question, in Bundle.wxs, see the following line: . It means that .NET 4 is the prereq to running the installer. If it is not installed, WiX launches a native bootstrapper which prompts the user and installs that package, then launches the custom installer UX when finished. So yes you can run the installer on machines that don’t have .NET installed. For more info, see the link to Heath Stewarts blog post that I included.
Now, if you want to conditionally install another package, in your bundle.wxs you can conditionally install a package based on the value of a variable, but you can set that variable in your UI like so: BootstrapperApplication.Engine.StringVariables[“someKey”] = “SomeValue”;
…although I think that may be more than what you need.
I had to move variables WixMbaPrereqPackageId and WixMbaPrereqLicenseUrl from Fragment to Bundle element to make the project build. Wondering what is the difference between our projects.
Not sure. For other bootstrapper projects that I have, I put the fragment in a separate (.wxs) file and include it in the Visual Studio project, and then just reference .NET from my bundle like via PackageGroupRef Id=’Netfx4Full’ and that seems to pull everything in just fine.
Got the answer from the mailing list. In my playfulness I removed everything else from the fragment, so there was nothing to be “pulled”, as you put it.
Thanks, this is really great example. I’m new to WIX and I want to make good looking installer for my application so this was really a good starting point.
I have one question and i cant find the answer anywhere so if you could plz help somehow, show me the right direction or something.
My installation is a bit more complicated than this from the example, i would like to have some user choices. Like for example licence agreement, features to be installed and similar. How would i proceed to do something like that, how would i pass the parameters set by user to the actual installer?
Thanks in advance for any kind of help
Skipina,
See the following two answers I posted on stackoverflow in regards to your question. They should help:
http://stackoverflow.com/questions/13623209/change-install-location-in-code-behind-with-custom-ui-code/13627962#13627962
http://stackoverflow.com/questions/10501995/pass-parameters-from-bootstrapper-to-msi-bundle-package/10504382#10504382
Thanks a lot, that’s exactly what i was looking for
Very good tutorial. Do you know how to modify your code to add an update feature? I’m trying different launch actions but cannot get update to work. If I change the version number in bundle.wxs or product.wxs and rebuild and install again a new bundle shows up in the Add/Remove programs list. What I would like is to replace the old bundle with the later in the Add/remove programs list.
Even tried to look in the WixBA source but cannot see how it’s done. It seems like a basic installer feature.
Thanks for help!
Make sure the upgrade code doesn’t change, and in your bundle try putting in a RelatedBundle element:
RelatedBundle Id=”UPGRADECODE” Action=”Upgrade”
If you are still having problems try to clear out any old installs, and you can always try using the standard BA to see if that upgrades properly.
You can also look at the WixBA source for the DetectRelatedBundle event to see how the detect a related bundle and what actions they take. I think they just tell it to install if it’s a newer version (no different than if there wasn’t a previous install on the machine).
Thanks for the quick reply! One problem though: I cannot see the line you tell me to add 🙂 It’s just a blank row in your reply.
I actually did try the standard bootstrapper ui and that works as expected so that’s why I think I missed something really easy.
Thanks again.
Sorry I wanted to say to add a RelatedBundle element but I couldn’t just paste the xml into the comment because it was filtered out. Anyway, I updated my comment above.
Thanks again. I’ve tried your suggestions but still cannot get it to work unforunately. Must be missing something basic here. The WixBA still doesn’t point me in the correct direction. I modified your code to show the “Install” button also when an installed package is detected (not just the uninstall button). If I then install the first bundle with version 1.0.0.0 it works just fine. But then if I change the bundle version to 2.0.0.0, then it detects an already installed package and the Install button is shown. When clicking the install button a new identical installer pops up and if I click install in that installer the new bundle is installed side by side with the old version in the Add/remove programs list. These are the only modification I’ve made and I find it really strange it doesn’t work. Any ideas?
hey having the same issue. Did you find out a solution?
I’m having the exact same issue as Exkoria. Can you think of any reason that would cause such as issue? Thank you.
If you check the log file(s) in your temp directory, does the log for the bootstrapper indicate that it detected a related bundle?
Yes, it does. However, the GUID it reports as the related bundle is not the same as my upgrade GUID.
I’m curious which command to use in the CustomBA. There’s the Install launch action, but there’s also a UpdateReplace action. However, when I try the UpdateReplace to do the update, the installer closes immediately without doing anything.
Thanks for your help on this.
[…] When it is running, It is calling a .NET-CustomAction which is showing a View (like this sample: https://bryanpjohnston.com/2012/09/28/custom-wix-managed-bootstrapper-application), where the User can choose some […]
Hi Bryan,
thank you very much for your example, it was very helpful and my setup is based on your design 😉
May you can help me with a question. It want to execute my internal msi with a transform. In your code the installlation is triggerd by:
Bootstrapper.Engine.Plan(LaunchAction.Install);
Bootstrapper.Engine.Apply(System.IntPtr.Zero);
As I need to launch the msi localized, it would use something like this instead:
Msiexec.exe/i MySetup.msi TRANSFORMS=MyTransform.mst
Is it possible to use this strategy without implemented a custom bootstrapper? Or is there a better way to apply the transforms?
Thank you very much,
Torben Schulz
Torben,
In your bundle (usually named Bundle.wxs), you would specifiy your .msi in a MsiPackage element. Then under that element you would add your transform in a Payload element. Then you would add a MsiProperty element, similar to “MsiProperty Name=’TRANSFORMS’ Value=’MyTransform.mst’. I would show example code but I can’t post xml in my comments.
Hello Bryan,
thank you for your response.
I imcluded my msts as payload and added the msiprop as you suggested. This works fine, but brought me to another question.
The user has to select a language in my wpf-ui, depending on his selection I want to apply a special transform.
How could I do this? Is there a way to conditionally select the values of an msipropery?
Thank you very much,
Torben
Torben,
In your WPF-UI you can set a string variable in the bootstrapper similar to: bootstrapperApplication.Engine.StringVariables[“MyVariable”] = “SomeValue”; Then in your bundle, you can reference that variable similar to: MsiProperty Name=”TRANSFORMS” Value=”[MyVariable]”
Wow! Thank you very much for your fast reply, Bryan. You helped me a lot. 🙂
I came from WISE-Setups to Wix, so most of the stuff is totally new to me, especially when using a bootstrapper.
Thats Perfect. Thanks. 🙂
Hi Bryan,
I’m playing with my bootstrapper-appI make good success, but some questions came up. Maybe I just miss a documentation 😉
1) I don’t want my bootstrapper-app to occur in the add/remove program list. I just want my nested msi to appear there. Currently both are visible.
2) Can I get the ProductName of my included msi in my wpf-bootstrapper-ui?
3) It takes lots of time to get my nested msi launched. Comparing with a former version generated with Wise it takes currently up to five seconds untill my internal setup ui occurs. It this just as it is or is there any possibility to quick it up?
Kind regards,
Torben
Torben,
1) You cannot prevent your bootstrapper from showing in add/remove programs but you
can prevent the individual packages from showing. To do so, on the MsiPackage
element set Visible=”no”.
2) I’m not sure how to get the product name from the msi. I thought I read a post
on StackOverflow by Rob Mensching the other day saying there was a way to do it,
but I can’t seem to find that now. There are some situations where you may want to
know what msi you are dealing with, and you can get the package Id (see my
OnDetectPackageComplete event handler), but I don’t think that is what you are
looking for.
3) I have noticed similar overhead. I think that is just the way it is. One thing you can do is to display a splash screen. See the SplashScreenSourceFile attribute of the Bundle element.
Hope that helps,
Bryan
Hi Bryan,
thank you again very much. As I can’t find the reply-Button in your post, I’ll post here. Hopefully you can help me once more, because I got the uncool feeling, that my intention to use the bootstrapper is not correct.
I just use a bootstrapper to allow the user to select a language, quite similar to the wise mechanism. A simple dialog with a combobox appears, the user selects his desired language and his choice I pass to the engine as you suggested earlier. The user should after selecting only click “ok” or “cancel” in my simple dialog, the whole rest should be handled by the internal msi ui, which works fine. I don’t want the user the decide wether he is going to install, deinstall or repair the installation in my bootstrapper setup. So the deadlock in my brain is, that during language selection I have no idea what the user wants. My internal setup is deinstalled or repaired properly, but I must, in case of uninstall, also remove the bootstrapper application from the program list.
So in my bootstrapper I always trigger an installation of my msi, never anything else.
Is it possible to check after the internal msi was handled wether it’s still available or has been removed and trigger a deinstallation of the bootstrapper app afterwards?
Thank you very much for your time, I really appreciate that.
Torben
If I understand correctly, you always want to perform an installation using the bootstrapper but need a way to handle uninstalling. You can continue as you are, just assuming you want to always perform an installation, except then handle the uninstall from Add/Remove programs. When someone uninstalls from Add/Remove programs, the bootstrapper knows that there is a request to uninstall. See the WiX source to see how they do it, specifically the event handler for the DetectComplete event. If you subscribe to that event, you may have a method like this:
private void OnDetectComplete(object sender, DetectCompleteEventArgs e)
{
// Uninstall
if (bootstrapper.Command.Action == LaunchAction.Uninstall)
{
TestBA.Dispatcher.Invoke((Action)delegate()
{
bootstrapper.Engine.Plan(LaunchAction.Uninstall);
});
}
}
Hi Bryan,
I have the following requirement
I need to develop an installer using Wix . I need to check whether .Net 3.5 SP1 is installed or not and if the prerequisite is not met, must show a messagebox(dialog) to the user telling that it is not installed – Do you wish to continue the install .Net, Once the user click OK, must install the .Net 3.5 and then continue with the rest of the installation.( My .Net MSI is inpackage)
Following are my questions?
a) Is it possible to implement the same in Wix with out using Burn(Bootstrapper)? If yes , how?
b) I can check whether for the .Net prerequisites from Wix MSI and can fail the installation if condition is not met. But cant continue with the installation of .Net.
c) I tried installing .Net component by invoking a custom action writen in C++ . But this approach doesnt seem to work since we having multiple MSIs running at the same time(Main MSI and the .Net MSI) and the .Net installation fails .
d) I tried using EmbeddedChainer Element in Wix. I have specified the .Net installer as the filesource. This approach also fails since multiple MSI instances are running.
I know i can achieve the functionality using Burn – but following are the issues i found with Burn approach
a) I need to double click an exe which internally invokes MSI whereas my requirement is very specific that starting point must be an MSI file.
b) As far as I know, we cant create a Burn bootstrapper application without a UI.
c)Using Burn- if prerequisites are not met, it will straight away install .Net componet without user consent.
Any suggestions are welcome. I am finding it very difficult to solve the problem.
Launching an msi from another msi may be possible but would be a hack and generally isn’t recommended/supported. I would recommend two options:
1) Use an msi and if .NET isn’t installed just alert the user and fail the installation
2) Use a bootstrapper such as Burn (or other tool) to chain the .msis. To use Burn, you don’t have to necessarily write your own UI, You could always use the standard bootstrapper application and see if that works for you.
Actually, you may want to investigate using the GenerateBootstrapper task in MSBuild. It will allow you to create a bootstrapper executable that will check prerequisites and launch msis and exes. I think that may be suitable in that it won’t give you a UI. However, if .NET isn’t installed, you can launch the .net installer. To continue, the customer would have to agree to install .NET but if they refused the installation would fail. This is what I use as my bootstrapper before Burn was released. There is no UI and it doesn’t embed the packages into a single executable.
Thanks Bryan ! GenerateBootstrapper was a good suggestion. Looks like it is working on Windows7 OS. I have created a bootstrapper which will check/download/install .Net 3.5 followed by the installation of MSI.
For unit testing, i ghosted an XP machine – uninstalled .Net3.5 SPI component . When i double click the setup.exe it is giving error ” setup.exe is not a valid Win32 application”. Any suggestions !
Maybe try using an older version of MSBuild (from an older .NET version). I’m wondering if there is a .NET dependency and that dependency existed on your Win7 machine but not your XP machine.
Tried with V2.0 – but still no luck !
Hmmm…That error sounds familiar though. It reminds me of troubles I had when Windows 7 came out and I got some funky error message on an executable that I had compiled on an earlier OS. The issue ended up being that I needed to add an appropriate manifest file so that the OS new that the binary was Windows 7 compatible. Your issue may not be related because you are going backwards, but I would imagine you could find out more searching around online. I’m don’t know what it is though.
Hi Bryan,
First of all, thanks for your article it helped me in getting started and understand few things.
I’ve created a custom managed boot strapper ,as a pre requisite it installs .net 4.0 if it doesn’t exist, after the .net installation which reboots the systems how do i resume my installation process.
thanks.
naren,
Fortunately I have been able to avoid reboots during installation so far, so I’m sorry I can’t be of much help. I’d try stackoverflow or the wix mailing list. This SO post also has some good info: http://stackoverflow.com/questions/16166186/wix-burn-after-restart-force-reboot-continuing-installation
Hi Bryan,
Finally i planned to install .Net 3.5 SPI using Wix Burn approach.
My plan is to include dotNetFx35setup.exe – to be a part of the package(in package) and i have specified it in ExePackage:SourceFile.
If .net 3.5 is not installed, i execute dotNetFx35setup.exe followed by invoking MSI.
Can you please review the below code and answer the 5 queries i have
Following are my questions
a) When should i specify payload elements.
b) When and why should i specify Bootstrapper.config file under Payload
c) Once i specify dotNetFx35setup.exe as the ExePackage::SourceFile, is it internally contained inside my bootstrapper.exe
d) Can i change the output type of my bootstrapper project(Visual studio 2012) to an msi file. I have seen that option in Visual studio properties.But it gives the error “This installation package cannot be opened”.Contact the application vendor to verify that it a valid Windows Installer pacakge”.
e) Simlar like a MSI Project, in Bootstrapper project can we show the messgebox/dialog if some conditions are not satisfied and cancel the installation process.
Code:
Ashish,
I can’t read your code because my blog doesn’t support xml comments (I’m just using a standard wordpress theme). Anway, here are some answers to your questions:
a)
You specify payloads under your BootstrapperApplicationRef to embed files in your bootstrapper application that used by the bootstrapper. These include your bootstrapper ui dll itself, as well as any third party libs it depends on, any license files (.net eula for example) as well as your BootstrapperCore.config.
You also specify payloads under your MsiPackages for files that get included with your.msi. For example, any transforms or external .cabs that aren’t embedded in the .msi.
b)
You always need to specify a BootstrapperCore.config for you custom managed WiX bootstrapper. Read more about it here: http://blogs.msdn.com/b/heaths/archive/2011/10/28/introducing-managed-bootstrapper-applications.aspx
c)
You can use the Compressed attribute of the ExePackage element to specify whether or not you want it embedded in the bootstrapper exe itself.
d)
You cannot change the output type (even though that option may make it seem that you can). WiX bootstrapper projects only produce .exes. Wix setup proejcts product .msis.
e)
You can specify conditions on to bootstrapper. I can’t type XML in my blog comments, but you would use the element bal:Condition and include a Message attribute for what you wanted to message to say. The inner text of the element would be your property/condition.
-Bryan
Thanks a lot Bryan ! Finally managed to resolve the .Net installation issues.
I have some queries on localizing Wix Bootstrapper and then invoking appropriate MSIs.
I have the following binaries
a) Wix Bootstrapper Exe – i have specified WixStandardBootstrapperApplication.RtfLicense
b) Localized MSI files for English,French and German cultures created using Wix MSI Project(Visual Studio)
I am planning to support the following locales – English,German and French.
a) How can I localize a Wix bootstrapper application . Is there any working example I can refer.
b) How can we pass the selected locate/culture information from the bootstrapper to the MSI such that it invokes the appropriate MSI.
I tried searching for the resources files for Bootstrapper ,but i could locate only English specific files.
Ashish,
I haven’t had to localize my bootstrapper but I’ll give you my thoughts. Here is a SO question regarding localizing a Standard Bootstrapper Application: http://stackoverflow.com/questions/11250597/creating-localized-wix-3-6-bootstrappers. If it is a custom bootstrapper UI, then you would localize it like you would a normal application. Regarding installing the appropriate msi, you would just put install conditions on each. See one of my comments to Torben regarding how to set variables in your UI, and then reference those variables in your bundle. Torben’s question was regarding Transforms, but the part about settting and reference variables would apply to your situation as well. You could also try creating a multilingual msi, although that’s not officially supported and is complicated to setup (I *think* this book has a chapter regarding multilingual msis: http://www.amazon.com/WiX-Developers-Guide-Windows-Installer/dp/1849513724).
Thanks Bryan!
Is there any way to get the name of invoked boostrapper exe by using any property in Wix? My boostrapper exe name will be dynamic and i need to write to a file . Name of MSI can be invoked using DATABASE property but i couldnt find anything for Boostrapper name.
I would accomplish this by passing the name of the bootstrapper to the msi as a property, then just reference that property in your msi.
If i specify Bundle Name=”Net35SPFinalInstaller” , boostrapper exe will get generated as Net35SPFinalInstaller.exe, still i can rename the final exe to something like Net35SPFinalInstaller1234abcd.exe –
After seeing the logs, i can seeing Variable: WixBundleOriginalSource = C:\Users\thoashis\Documents\Visual Studio 2012\Projects\Net35SPFinalInstaller\Net35SPFinalInstaller\bin\Debug\Net35SPFinalInstaller.exe , so can i rely on value of WixBundleOriginalSource and pass it to MSI as a property.
I think officially your not suppose to rename the bootstrapper after compilation (at least if you do, your logs won’t match up to the exe name). If you do rename the exe and want to know what the actual name is, you can probably use reflection to get the actual file name, then set that name in a variable and set it to a property as I specified before.
Hi Brayan,
I’ve created a custom bootstrapper (in wpf) with the help of your article, im using this bootstrapper to install some prerequisites (.net4.0 etc)
and then install my product msi, the installation is working fine , but on installing the bootstrapper isn’t unisntalling the msi , and also the bootstrapper entry isn’t being removed from control panels programs and features list.
I”m calling bootstrapper.engine.Plan(LaunchAction.Install); for unistalling.
is there anything else that i should do to uninstall the msi on unistalling the bootstrapper.
thanks.
naren
Hi Brayan,
I’ve created a custom bootstrapper (in wpf) with the help of your article, im using this bootstrapper to install some prerequisites (.net4.0 etc)
and then install my product msi, the installation is working fine , but on un-installing the bootstrapper isn’t unisntalling the msi , and also the bootstrapper entry isn’t being removed from control panels programs and features list.
I”m calling bootstrapper.engine.Plan(LaunchAction.Install);
for unistalling.is there anything else that i should do to uninstall the msi on unistalling the bootstrapper.
thanks.
naren,
You need to use LaunchAction.Uninstall. See one of my recent comments to Torben regarding uninstalling via add/remove programs.
Hello Byayan,
thanks for the reply.
i’ve mistakenly put LaunchAction.Install instead of LaunchAction.Uninstall , sorry for that.
I’m passing LaunchAction.Uninstall for uninstalling,
I’m using this on uninstall command is there anything else i should check ?
In log files i can see the uninstall action planned for my package
[18C8:16CC][2013-05-15T17:42:28]i201: Planned package: MyPackage, state: Present, default requested: Absent, ba requested: Absent, execute: Uninstall, rollback: Install, cache: No, uncache: Yes, dependency: Unregister
and also there are no log entires between apply.begin and apply.end
[18C8:16CC][2013-05-15T17:42:28]i300: Apply begin
[18C8:16CC][2013-05-15T17:42:28]i399: Apply complete, result: 0x8007015e, restart: Required, ba requested restart: No
naren,
I would keep digging through the logs as they will help you figure out what is going in. You should have a log for the bootstrapper and a log for each .msi being installed. I’d go over them thoroughly and see if something is failing at some point and causing a rollback. Also, it may be possible that you are actually uninstalling, but due to previous testing, there is a previous bad installation stuck on your computer. You can try uninstalling your msi via command line (msiexec /x productCode) and at times i’ve resorted to digging around in the registry, manually deleting keys and cleaning up installs (do so at your own risk). If you think the case could be a possible bad previous install, you may try installing on a separate computer to see if it uninstalls (although risking not being able to uninstall on that machine as well).
Hello Brayn,
thanks for the quick reply.
I’m not finding any “dependency found” related issues in the log file.
Im testing on a formatted computer.
I can uninstall the .msi from control panel but not through the bootstrapper also i cant uninstall the bootstrapper itself.
While installing two log files are getting created (one for bootstrapper and one file .msi) but for uninstalling only one log file is getting created (only for bootstrapper)
I’m not finding any other helpful information in the boostrapper log.
are there any specific events that i should check in the bootstrapper
thanks.
Hello Bryan,
we have put ExitCode Behavior=”scheduleReboot” for one of the prerequisite package , because of this the complete uninstallaton is happening only after rebooting,
i’ve found it here
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/How-to-uninstall-Burn-bundle-td7579345.html
thanks
Good to know, thanks.
HI Bryan,
I am planning to create a multilingual MSI. I have created MSI file for the English local and have created MST File for German using MSITran.exe .
I am invoking the msi from the bootstrapper. I specify German language to be shown in the MSI ui by specifying the following in the WIx boostrapper project
where Trans.mst is the transformation file for the German.
If I hardcode the full path of mst file as above , when I invoke MSI from bootstrapper it will show the German language strings.(Since this file is present locally).
I wanted to embed Trans.mst within the Boostrapper exe and I know I can do that by specifying Payload.
In that case, can someone guide me in telling how to set value of TRANSFORMS property such that it can point to German Transform file Trans.mst file which is contained inside Boostrapper or is there any better way to do this.
Currently launching German strings is working only the local machine whereas it is not working on remote machine.
On remote machine , it gives the error “ Error applying transforms. Verify that the specified transformed paths are valid”
Ashish,
Make sure you specify the transform is a payload of the MsiPackage and not the Bootstrapper itself. Also, see one of my previous comments to Torben regarding setting the transform property from the bootstrapper.
Correct! I have specified the transform to the MSIPackage. What should i specify the value for TRANSFORMS property – should it be the id or name of the Payload.
It should contain the name of the file.
Thanks Bryan! It is working correctly now !
Bryan,
Hi. I am relatively new to WIX (and .net) and am working on reimplementing a multi-page WIX-based installer using your managed-code model. I have the basic code working and was wondering if you could refer me to an example that presents multiple pages such as a welcome/EULA and Options. The Options page is accessed via a button
The best custom managed WiX bootstrapper example out there is the one used to install the WiX Toolset itself. I don’t know if it has exactly what you want, but if you look at the code it might give you an idea as to what to do. Download the WiX source code and look in the folder src\Setup\WixBA.
Hi Scott,
check out the Laika42 Wix Toolset Extension in Visual Studio Gallery.It creates a WiX custom bootstrapper which you can extend.
Maybe this is what you are looking for.
Regards,
Mia
Hi Mia,
I have been using Laika42. Its a very good extension. Unfortunately there is no documentation for extended control. I wanna show my feature selection from my MSI in the boostrapper as a checkbox option. Can u give some hints on this?
Is there any way or tool by which we can view the individual file sizes that is contained inside a Wix bootstrapper. My bootstrapper internally contains .Net installer and MSI , but when viewed using 7 zip it is showing u0 ,u1 etc and we cant determine what is contained inside each file.
No but if you can’t just look at the msis before you build the bootstrapper you can always run the bootstrapper itself and hijack the msis from the temp directory where they get unpacked. If you need to look inside the individual msis, use a tool such as Orca.
Hi Bryan,
I have a Wix Bootstrapper Exe which internally invokes an MSI files.
Can you please help me to ensure that only a single instance of Boostrapper will get installed and will be seen in ARP.
I have seen that if i makes comes changes to Bundle.wxs, even though the version number and the Upgrade code are the same, it is able to install the second instance.
Try adding a RelatedBundle element to your Bundle.wxs file. Set the Id attribute to your upgrade code guid, and set the Action attribute to “Upgrade”.
Hi Bryan,
The Execpackages chained in my bootstrapper fail to rollback. The log file
says:
Error 0x80070003: Failed to CreateProcess…when it starts applying the
rollback package.
Realized that the directory created for the execPackage payload in C:\ProgramData\Package Cache which holds the Execpackage gets deleted the moment I set Result.cancel in order to trigger rollback.
But Im not able to figure out why.
Have posted this question in multiple forums, but no luck 😦
Roopa,
I haven’t run into that scenario and am not sure what could be causing it. If you are digging and still can’t find an answer I’d maybe try stackoverflow or the wix mailing list. Sorry I couldn’t be of much help.
Bryan
In your example solution, I have added a text box for installation path in MainView, And I have created a property called InstallPath in MainViewModel and did the Twoway binding to the textbox in the view.
in the BA I am setting like below,
viewModel.Bootstrapper.Engine.StringVariables[“MyBurnVariable1”] = viewModel.InstallPath;
InstallPath is always empty, why? what should I do to solve this?
Log the value of viewModel.InstallPath and if it is empty then something is wrong in your binding.
in MainViewMode.cs I added the installPath property as below
private string installPath;
public string InstallPath
{
get { return installPath; }
set
{
installPath = value;
RaisePropertyChanged(“InstallPath”);
}
}
in TestBA.cs I added below piece of code
MainView view = new MainView();
view.DataContext = viewModel;
this.Engine.Log(LogLevel.Verbose, “My String: ” + view.textBox2.Text); viewModel.Bootstrapper.Engine.StringVariables[“MyBurnVariable1”] = viewModel.InstallPath;
view.Closed += (sender, e) => BootstrapperDispatcher.InvokeShutdown();
view.Show();
And xaml for textbox is
And log content is
[1DE8:320C][2013-07-17T01:52:23]i101: Detected package: Netfx4Full, state: Present, cached: None
[1DE8:320C][2013-07-17T01:52:23]i101: Detected package: DummyInstallationPackageId, state: Absent, cached: None
[1DE8:320C][2013-07-17T01:52:23]i199: Detect complete, result: 0x0
[1DE8:29B4][2013-07-17T01:52:23]i000: My String:
[1DE8:29B4][2013-07-17T01:52:23]i000: Unsetting variable ‘MyBurnVariable1’
[1DE8:320C][2013-07-17T01:52:43]i200: Plan begin, 2 packages, action: Install
xaml for the textbox is
textbox xaml is
“”
textbox text binding is
Text=”{Binding Path=InstallPath, Mode=TwoWay}
Rahul, try setting that variable in your viewModel instead of in your TestBA.cs file (for example at the beginning of your InstallExecute method). You can also put the following line in your bootstrapper (temporarily) so that it launches a debugger so you can debug your app and see what is happening: System.Diagnostics.Debugger.Launch();
Bryan, It works. Thank you very much!!
Hi Bryan,
I am new to Wix and I would like to ask you a couple of questions as I can’t get this .Net prerequisite thing to work.
1) I thought that if we define ExePackage and place a valid SourceFile location with Compressed attribute to yes that that package will be embeded inside installation. So why do we need a downloadUrl if the prereq we need is already inside .exe installer? I get a linker warning that the file is embedded and that a download url will be ignored.
2) I did everything just like you except for the .cs files and just can not get it to work. Download url was ignored by linker as .Net was detected as embedded inside installation. My log file:
Loading managed bootstrapper application.
Error 0x80131902: Failed to create the managed bootstrapper application.
Error 0x80131902: Failed to create UX.
Error 0x80131902: Failed to load UX.
Error 0x80131902: Failed while running
3) It will do just fine for me if I could get bal:Condition to work but I can not do that either. I wrote bunch of bal:Conditions with specific messages and conditions like: 0, 1, 1=2, VersionNT = v5.0 etc. It just don’t pop up a message. I need a condition for .Net prereq so I wrote:
Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)
where those variables are registry searches (copied from you).
Problem is that I think it never comes to evaluation of these conditions as I can not find any mentions of it in the log file.
4) Not related to .Net prereq installation but maybe you will know the answer to this question too. Do you know if it is possible to uninstall specific packages using BootstrapperApplication.Engine.Plan(LaunchAction.Uninstall)? I tried to set detectCondition for exe packages to true and InstallCondition to false, for MSIs only InstallCondition to false before calling Plan(LaunchAction.Uninstall). It seems that its current behaviour is that it will uninstall all cached packages. I suppose that packages are cached during install phase.
If I change LaunchAction to Modify it works as I wish it but I need it to also remove Bootstraper record from Add/Remove Programs.
Thanks in advance!
Hi Brayn,
Thanks for a good working example. While playing with TestBA Bootstrapper first I installed 1.0.0.0. Then I incremented version to 1.0.0.1 and logged the process. Here is the part where -uninstall -quite command line was passed during upgrade:
[1A44:1E54][2014-02-24T17:47:22]i301: Applying execute package: {f1d57671-5e3d-4be7-908f-5a47e72737d9}, action: Uninstall, path: C:\ProgramData\Package Cache\{f1d57671-5e3d-4be7-908f-5a47e72737d9}\BootstrapperSetup.exe, arguments: ‘”C:\ProgramData\Package Cache\{f1d57671-5e3d-4be7-908f-5a47e72737d9}\BootstrapperSetup.exe” -uninstall -quiet -burn.related.upgrade’
Instead of quietly uninstalling, it would display the Uninstall Dialog. And if I click Uninstall, it would uninstall 1.0.0.0 and then application would be upgraded to 1.0.0.1.
Can you please guide how to make it understand its command line arguments and do the process without showing Uninstall Dialog box?
Thanks a bunch.
My example was minimal so it left out a lot. If you want to implement quiet uninstall, then in TestBA.cs, don’t create and show the view if Command.Display == Display.Full. Then in your bootstrapper view model, create a method that runs whenever the detect complete event is fired and if you are uninstalling, automatically uninstall, similar to: private void OnDetectComplete(object sender, DetectCompleteEventArgs e)
{
// Uninstall
if (Bootstrapper.Command.Action == LaunchAction.Uninstall)
{
IsThinking = true;
Bootstrapper.Engine.Plan(LaunchAction.Uninstall);
}
}
Hey Farukh, can you tell me what I should change in this tutorial to make it do a proper major upgrade? Really stuck with this man. Badly need your help.When I perform a major upgrade, i incremented the EXE version as well as the MSI version. But though the update does work, it still leaves the old EXE there. Please advice.
hey having the same issue mate. Did you find any solution?
In these two years, I’ve developed a Managed Bootstrapper with WPF based UI, while handling all such things in it…
you should better subscribe to Wix-User’s list. Visit FireGiant.com.
Here is the Upgrade markup. Do see documentation as well:
Hi Bryan,
Hope you are doing well. I have a question regarding uninstall behaviour in XP using Wix.
We are using Wix MSI for doing installation/uninstallation of our application. Currently our application is supported from Windows XP and above. As a part of uninstallation, we are removing Gui application from system tray. But we are finding two different behavior for XP vs Non XPS
Non XP – Vista and Above (eg: Win7) – Here ,when we remove uninstall from Add or Remove Programs, gets a pop up that Gui application needs to closed before continuing the install. I select “Automatically close applications and attempt to restart them after setup is complete” and uninstallation is completed successfully and everything works fine.
XP – When I invoke uninstall from Add or Remove Programs, I didn’t get the pop up that Gui application needs to closed. Uninstallation removes all the files from the installation directory but application is still seen in the system tray.
Here are the questions
a) Why the different behavior seen in Windows XP? Is it since Restart Manager is not present in XP.
b) How can I get Windows 7 behavior in Windows XP (ie getting pop up that Gui application needs to closed)
c) In Windows7, how can I prevent “Gui application needs to be closed” from not appearing.
d) For XP, I have added the below code to remove Gui during uninstallation and found working. Can someone please comment if I am doing correct or something wrong with the below code.
What I am basically aiming is the same behavior in both XP and Windows7 operating systems.
My guess is the different behavior is because of different versions of Windows Installer. I’m not sure how or why you would want to change the behavior your are noticing on Win7. Depending on how you uninstall, a silent uninstallation should not show any dialogs.
Hi Bryan,
Ideally I shouldnt change the behavior of Win7 you are right. But I cant go for silent uninstall since I am invoking it Add or Remove programs to uninstall. Have to tried using util:CloseApplication?
I haven’t used that but you could try. You could also try creating a custom action to check if the process is running and kill it. Or if you have a custom bootstrapper UI, you can check if the application is running and end it from there.
Hi,
Great article, I managed to build a custom installation with localization and everything works great. But, for some reason, after the installation (of the MSI package completes) it reopen few more times the MainView screen. I tried to debug and before each screen open the ExecPackageBegin for package with number ID that I have no clue about. Any idea where it can come from? What I can do?
I’d check the logs to see if it gives you a hint as to what is going on. I wonder if there is an older installation on your machine that is in a weird state (from early testing\development of your bootstrapper) that needs cleaned. That is just a guess though, could be a totally different issue.
Hi Bryan,
I have three MSIs and a Burn UI which gives user the choice to select which MSI to install/uninstall via checkboxes selection.
I have added a bundle variable for three checkboxes and change the variable values based on the checkbox selection.
Then added InstallCondition attribute in msipackage element and assign the variable value in it. Installation is working fine, it installs selected MSI files. But I stuck to handle this in uninstallation.
How can I handle the condition on uninstall for removing selected MSI files?
Generally speaking, uninstalling the bundle will remove all the packages it installed, unless they are marked permanent.
Hi Bryan,
I am very new to wix. I tries something on your lines and am encountered with the below error
Duplicate symbol ‘Container:WixUXContainer’ found.
This typically means that an Id is duplicated.
Check to make sure all your identifiers of a given type (File, Component, Feature) are unique.
C:\src\wix38\src\ext\BalExtension\wixlib\wixstdba_platform.wxi
Could you please let me know what would that mean?
Hi Bryan,
I am very new to Wix and am trying something on your lines. But when I build the Bundle.wxs, I am thrown an error as below
Duplicate symbol ‘Container:WixUXContainer’ found.
This typically means that an Id is duplicated.
Check to make sure all your identifiers of a given type (File, Component, Feature) are unique.
C:\src\wix38\src\ext\BalExtension\wixlib\wixstdba_platform.wxi .
I have kept the bundle.wxs simple as below
Could you please suggest something?
Not sure based on the info. You could try posting your code, error and any other helpful info to StackOverflow.
Hi Bryan,
First let me start off by saying that you for this how-to guide. Probably the only one on the internet thus far.
I have a question about whether or not I can eliminate the two WIX variables from my install? If so, how shall I go about doing so?
Thanks InAdvance.
You mean WixMbaPrereqPackageId and WixMbaPrereqLicenseUrl? Those are necessary for a managed bootstrapper.
Thank You. I realized when I entered the WixMbaPrereqPackageId and WixMbaPrereqLicenseUrl variable IDs, they did not show up in my original post. Kinda weird, but you answered my question spot on.
Bryan,
I happen to run across an obstacle with BA in general. Using your TestBA app, I would like to add radio buttons The only problem I have is, how to reference the menu selections in WIX? I have two MSIs I would like to include in my bootstrapper app, but need only one msi to run when a user makes a selection. Is that possible?
Thanks Again
Hi Bryan,
How can I reference in my MSI a variable that I’m passing in from my bootstrapper. For example, I have the following text in my bundle.wxs file:
within Bundle
within MsiPackage
Now, in my MSI where ever I have $(var.msiVersion) I would like to use the Msiproperty variable baVersion from my BA bundle.wxs
Thanks InAdvance
lino76,
The xml you tried putting in your comment didn’t come through, but I believe the following stack overflow Q&A describes exactly what you are asking: http://stackoverflow.com/questions/15019135/wix-how-to-access-change-installation-directory-in-managed-bootstrapper
Let me try this again…
This time I remove quotes and open and closing tags
within Bundle
Variable Name=baVersion bal:Overridable =yes Type =string Value =123456789
within MsiPackage
MsiProperty Name =baVersion Value =[baVersion]
Hi Bryan,
I have one Bootstrapper CustomAction which is Console and it was working fine
Recently i added one more conosle application which i used the same BootsrapperCore.dll and in BootstrapperApplicationRef I referenced bootstrappercore.config which is updated with new assembly.
But i’m getting error like below
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\ProgramData\Package Cache\DD1CAFC84EABF34ED58FEA8C3E92B30F6E471178\ATL.Trebuchet.IISActions.exe
— A detailed error log follows.
=== Pre-bind state information ===
LOG: DisplayName = BootstrapperCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad
(Fully-specified)
LOG: Appbase = file:///C:/ProgramData/Package Cache/DD1CAFC84EABF34ED58FEA8C3E92B30F6E471178/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = ATL.Trebuchet.IISActions.exe
Calling assembly : ATL.Trebuchet.IISActions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: BootstrapperCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/ProgramData/Package Cache/DD1CAFC84EABF34ED58FEA8C3E92B30F6E471178/BootstrapperCore.DLL.
LOG: Attempting download of new URL file:///C:/ProgramData/Package Cache/DD1CAFC84EABF34ED58FEA8C3E92B30F6E471178/BootstrapperCore/BootstrapperCore.DLL.
LOG: Attempting download of new URL file:///C:/ProgramData/Package Cache/DD1CAFC84EABF34ED58FEA8C3E92B30F6E471178/BootstrapperCore.EXE.
LOG: Attempting download of new URL file:///C:/ProgramData/Package Cache/DD1CAFC84EABF34ED58FEA8C3E92B30F6E471178/BootstrapperCore/BootstrapperCore.EXE.
LOG: All probing URLs attempted and failed.
Please help to figure the problem
Hi bryan,
MSI was not uninstalled during uninstallation.Please give solution for this
Log File :
Error 0x80070643: Failed to uninstall MSI package.
Error 0x80070643: Failed to execute MSI package.
Error 0x80070643: Failed to configure per-machine MSI package.
Thanks in Advance
Thanks for great blog on managed bootstraper,
I want to launch application after the installation finishes.
Thanks in Advance
Pankaj Deharia
That’s easy :). On successful installation, construct a string with your full file path name of you process/exe, then call Process.Start(–>executable name here<–);
I do it, works fine.
Yes, in common case to construct the full file path name need to know MSI property value of installation folder. How to get it from MSI in Bootstrapper application?
Very useful application. I extended it to my needs, works awesome. I would like to remove the dependency on MVVM Light Toolkit. How difficult or easy it is??
Thanks,
Karthick
Very easy. I used the MVVM Light Toolkit to save me from creating an ICommand implementation for my commands (see the RelayCommands in my sample code). Just search for implementing ICommand in MVVM and there are many examples out there.
Hello Bryan, I think your article is the only complete managed bootstrapper sample. I was so excited and tested it over and over. Then I decided to debug TestBA.dll to see if I could run this app silently.
However even if I set the break point to every method, it didn’t hit. So I read all replies to see if anyone asked how to debug, but your mentioning about “System.Diagnostics.Debugger.Launch();” was all. I guess everyone knows how to, so I feel embarassed.
Anyway, here is how I tried to debug:
In TestBA property, I set the fullpath of the bootstrapper exe as Debug’s “Start external program” and hit F5, but it didn’t work. I even attempted to attach this debuggable DLL to the boostrapper’s process and no avail.
Would you guide me how I can debug TestBA?
One way to debug is to manually attach the debugger. So for example, if your installer is named “TestBA.exe”, then you can launch your installer, then from Visual Studio select Debug > Attach to Process and then choose “TestBA.exe” from the list of processes. This works for me for most scenarios, however because you attach the debugger after you launch the installer, this has some drawbacks. If you need to debug some code that executes when the installer is starting up, then you would use System.Diagnostics.Debugger.Launch(). You can put that line somewhere in the beginning of your installer and it should cause the debugger to get launched when it gets executed.
Thank you for quick reply Bryan. That’s what I was doing too. I thought I was doing something wrong but since you convinced me, it dug dip and found that the WXS grabbed the DLL from the old place. Now I can debug. Thank you very much again Bryan!!!
Hi Bryan,
Using Wix Standard BA, is it possible to add a checkbox, such as, “Do not show this dialog again”, so that it runs silently when the users run the upgrade in the future?
I don’t think so. You would have to add some type of logic to be able to check a flag and if set, run the installer silently, and I don’t think you can do that in the Standard BA.
tnx, great post
[…] https://bryanpjohnston.com/2012/09/28/custom-wix-managed-bootstrapper-application/ […]
Hi Bryan, thank you for your article.
As I understand I can set property values from c# to MSI installer in 2 steps: c#->bundle variable->msi property.
How I can read property value from MSI file inside of WPF code?
For example: I need to read default property value from MSI file, show it in WPF control, user can change it and then pass it back to MSI.
Oleg, look at how the variables get set. Reading them back in is very similar.