Skip to content

Concepts

Richard Martin edited this page Jul 30, 2024 · 5 revisions

The Bundle

A bundle is a Windows executable that installs one or more packages. It's not named setup.exe. It has a more specific file name to avoid the build error WIX0388 - The file name 'setup.exe' creates an insecure bundle. Windows will load unnecessary compatibility shims into a bundle with that file name. These compatibility shims can be DLL hijacked allowing attackers to compromise your customers' computer.

It's similar to an executable zip. The executable portion – the part that Windows will run – will extract files that have been packed into the exe. One type of file packed is our bootstrapper application, or BA. The BA is a single DLL, but can have as many dependencies as you wish, and these dependencies can be any kind of file you want. It might be fun to keep these files down to a reasonable size and count, but how you organize the BA is ultimately up to you. Aside from the BA, all of the installation packages you wish to deploy are also packed in there, so they can be extracted, too. After extracting your BA, it will be run.

The bundle is not your BA. The bundle contains everything – your BA, packages, plus some handy code that deals with extraction and starting your BA. So, when you see me referring to bundle and BA in the rest of this tutorial, you know which bits I'm referring to.

The Bootstrapper Application

A bootstrapper application, or BA, manages the planning and execution of the packages that are included in the bundle. It normally has a UI. But be aware that your UI may not always be needed and may not be displayed under some circumstances. Your BA should be able to handle things on its own without a user telling it what to do.

The Burn Toolbox

Before we get into how to build a BA, let's open the WiX present up and see what we got for our v4 birthday! Surely there are some pretty esoteric things in there that will be useful for very specific situations, but which ones are the hammers and screwdrivers – the tools you'll find most useful when building a BA?

  • IEngine – The WiX engine is made up of native code whose functionality is exposed through this interface. This gets your install running and provides other important features.
  • BootstrapperApplication – This is the entry point into your own bootstrapper application. It's main feature, though, is providing events that are raised while the install is running. Handling these events will allow you to control the install of your bundle.
  • BootstrapperApplicationData – This class gives you access to data about the packages that are in your bundle.
  • IBootstrapperCommand – A class abstracted by this interface lets you access the commands passed to your BA by the engine. If you wish to expose every option your BA supports through command line parameters, then you'll appreciate this tool.
  • BaseBootstrapperApplicationFactory – It's a class factory that will help get your BA wired up.

What to do with them?

So, we rummaged through the toolbox and found a handful of gizmos that look like we use them for... something. But what? Let's go over what your BA needs to do. It needs to perform these steps in this order.

  1. Start up – Models and UI should get instantiated and subscribed to events. This can be done in a class factory, but however you do it, there's usually a lot to do.
  2. Detect – You'll need to get the detect phase running and record any useful data you discover during this process. For example, has your software already been installed? If so, what version is installed? And other stuff that's handy to know about.

Tip

You often get the detect phase running before completing the start up. It runs in the background, so after you start it, you'll want to present the UI to the user (if appropriate) and start a message loop. Once your message loop is running, you can pat yourself on the back for completing the start up.

  1. Maybe get the user involved - After figuring out what's installed, the next step is to choose an action to perform. For example, install, uninstall, repair, upgrade, etc. If your BA is presenting a UI, it might be a good idea to ask the user their thoughts on the matter.
  2. Plan – The next step is to plan the chosen action. This is the point where, as far as the end user is concerned, "the install is running". It continues to run until the apply phase completes. Behind the scenes, though, planning is done before apply starts.
  3. Apply – Once the plan is established, it's time to start deploying your software. You normally start the apply immediately after planning has finished.
  4. Tear down – You'll need to tear down any UI, stop the message loop you have running, and shut down the engine.

If you're thinking about organizing your code, you might use the list above as inspiration. I like the idea of splitting out the workload into these phases, especially Detect, Plan, and Apply. It's easy to end up with god classes when tackling a BA, so splitting the work out into smaller pieces helps.

Message Loop?

https://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows

If you're unfamiliar with a message loop and are confused by the comments about that above, then let's go over it a little. You'll need to know something about it, like how to start and stop a loop. As Wikipedia mentions, it's essentially a do while or for loop. This is typically hidden from the developer when building a Windows Forms or WPF app. The app starts the message loop behind the scenes and when the user closes the last window in your app, the message loop is stopped for you. While the loop is running, "messages", or UI events, are placed in a queue that are processed by the loop, again without the developer really being involved. Sure, we know about stuff like the Dispatcher class that helps us dispatch messages to the loop, but usually we're protected from the dirty nitty gritty some. We're going to get a bit more hands-on with the message loop in our BA.

If we'll have a loop running... what if we used that loop to our advantage? What if we had code that looked like this?

Startup()
RunLoop()
TearDown()

If that RunLoop method above is blocking, because it can't exit until we say so, then TearDown won't execute until we're ready for it. We can also hijack the thread that starts up our app and use it as the thread that processes UI messages (i.e. events). We can even install software while that loop keeps chugging away, even if we don't have a UI to display.

No UI? What's That About?

I've mentioned several times that your UI may not get used. Or, more correctly, you may not want to display it under some circumstances. Additionally, you will want to consider passive mode.

  • Passive mode - Burn bundles support the -passive command line parameter. If used, UI displaying progress is expected, but the install should proceed and exit automatically. You decide whether to get the user involved if a problem occurs. You should consider why your users would want to run your bundle passively. If you're deploying a consumer facing app, then the user may appreciate knowing that the install failed and, if their input could help it succeed, being asked how to proceed. But if your deployment isn't consumer facing, then you should know your customers well enough to know why they'd use this mode and what they expect from it.
  • Silent mode – Burn bundles also support the -silent, -quiet, -s, and -q command line parameters. In silent mode, no UI is displayed for any reason. The installer must handle all problems without user input. A good option to indicate a failed install is to return a win32 error code when the app exits.
  • Embedded mode – And then there's this. Surprise! This can happen when your BA needs to run your bundle, or more practically, an older version of your bundle. For example, you're handling an update for your software. One very good option to support an update is to run your old bundle to uninstall, then the current bundle can do a fresh install. In this scenario, WiX will run your old bundle with a command line parameter letting it know it's running embedded. Your old bundle can run silently and send progress to your new bundle so it can handle the progress display.

Architecture (x86 vs x64)

One of the cool features introduced with WiX 4 is support for building x64 bundles. But architecture can cause confusion, so let's spend a little time on it. As mentioned previously, the bundle is an executable (exe file) and the BA is a class library (dll file). Just like any other .NET product you build, the architecture of the exe and any dll dependencies must match. If you wish to target x64, the bundle and BA architectures must both be set to x64. The same applies to x86, of course. But what about the packages (msi files) included in the bundle? The architecture they are intended to support does not matter. It turns out they aren't executed by the bundle. They can't be. They're just databases. They're handled by Windows Installer which builds and executes scripts based on the data in the database. The bundle schedules each database and hooks up to the Windows Installer API to monitor the execution.

But you have an exe file that needs to be deployed by your bundle? These files aren't packages, they're bundles. WiX can handle them, too. It can run these as external apps. Because these are run externally, the architecture they target doesn't matter, either.

So, when it comes to choosing an architecture, we're left with one rule. The target architecture of your BA must match the architecture of your bundle.

.NET Framework or .NET Core?

WiX 3 supported .NET Framework bootstrapper applications. WiX 4 adds support for .NET Core. Core adds some additional challenges. It's not a lot, and we'll cover them later. But you should consider if the additional effort is worth it. Supporting the version of .NET that comes pre-installed with Windows will keep your bundle smaller, but you won't be able to use the features of the later .NET versions.

Either way, this tutorial covers both options.

Help From the WiX Team

The WiX team has put together a series of tests and/or examples of bundles hosting .NET Framework and Core bootstrapper apps.

wix/src/ext/Bal/test/examples/

The file examples.proj demonstrates how to publish the .NET Core variants.

wix/src/ext/Bal/test/examples/examples.proj

Previous: Home || → Next: Solution Overview