-
Notifications
You must be signed in to change notification settings - Fork 179
Managed Setup Model
All samples in this document are from the '<Wix#>\Samples\Managed UI' folder. All of the samples are also reflected in the Visual Studio templates available as a "WixSharp Project Templates" extension.
The objective of Wix# is to bring MSI authoring inline with the other software development/programming activities. The initial Wix# development was mainly about integrating the authoring process with the C# syntactical model and C# and WiX compilers. However it was only a part of the problem that WiX# was trying to solve. A more fundamental task was to change the over-engineered and often outdated MSI programming model. Thus Wix# allows avoiding definition of the MSI/WiX elements that have low (or no) deployment value and yet can be generated automatically. Hence IDs, elements associations are optional for the cases when Wix# engine can establish them without user involvement. MSI Components are even become completely hidden without any exposure to the user. Another dramatic improvement is the ability to define Custom Action implementations directly in the build script.
However two very distinctive MSI authoring activities for quite some time remained very consistent with the raw MSI development experiences: Custom Action scheduling and standard/custom UI. However this gap has been closed with the release of the event-driven custom action scheduling and a complete set of managed (WinForm based) standard MSI dialogs. From that moment a fully managed WiX/MSI setup definition became possible. These two major features are the essence of Managed Setup programming model.
The access to the Managed Setup programming model is implemented via a dedicated Wix# project type WixSharp.ManagedProjects. It's important to note that ManagedProjects doesn't replace WixSharp.Projects. It only extends it with new functionality without affecting the existing one.
Note that all code samples in this document are from the "Managed Setup" samples included in the product downloadables.
When it comes to scheduling Custom Actions MSI allows extremely high level of granularity. A custom action can be scheduled at any of the ~160 possible "execution steps" (before/after ~80 standard actions). Why such an extreme resolution?
The answer is in the limited nature of MSI runtime. Every custom actions is completely isolated not only from other custom actions but also from the MSI runtime. There is no way for the custom action to become "aware" about its position on the execution time-line or about any other action outcome. Every custom action is invoked in the individual rundll32.exe process. The only way to interact with any other installation component is by writing and reading string values into session properties collection. Though Deferred Actions don't even have the direct access to the MSI session at all. Concurrency control ultimately simplistic: either blocking single action at the time or fully asynchronous. Thus MSI API needs to leverage these limitations by offering a high resolution scheduling.
However Wix# is different. While inheritably exhibiting all MSI limitations it hides (thanks to the power of .NET) them behind Wix# API layer and by doing so dramatically simplifies the whole authoring process. And this is exactly what the Managed Setup concept is all about.
Managed Setup is a "lean setup", which delivers event-driven runtime behavior instead of action-scheduling normally enforced by MSI. Instead of dealing with ~80 execution steps Managed Setup recognizes only three most important installation events: Load, BeforeInstall and AfterAinstall. The diagram below demonstrates the "placement" of these events with respect to the major installation stages.
Thus ManagedProject class allows developers using an event-driven programming model so common in the main stream application development.
Note that ManagedProject also has other three events: WixSourceGenerated, WixSourceFormated and WixSourceSaved. The use of prefix 'Wix' indicates that these events are raised not at runtime (msi execution) but at compiletime (generation of WiX sources). See 'XML Injection' article for more details.
The following code illustrates how to use the runtime events events:
project.Load += msi_Load;
project.BeforeInstall += msi_BeforeInstall;
project.AfterInstall += msi_AfterInstall;
...
static void msi_Load(SetupEventArgs e)
{
MessageBox.Show(e.ToString(), "Load");
}
static void msi_BeforeInstall(SetupEventArgs e)
{
MessageBox.Show(e.ToString(), "BeforeInstall");
}
static void msi_AfterInstall(SetupEventArgs e)
{
MessageBox.Show(e.ToString(), "AfterExecute");
}
With the event handlers you are no longer required to have the CustomActionAttribute
placed in your code. It is all will be done for you by the Wix# compiler. The even handlers will be invoked at runtime according the following scheduling:
Load -> When.Before, Step.AppSearch
BeforeInstall -> When.Before, Step.InstallFiles
AfterInstall -> When.After, Step.InstallFiles
Inside of the event handlers you have the access to the all session objects via SetupEventArgs
argument:
static void msi_AfterInstall(SetupEventArgs e)
{
if (!e.IsUninstalling && e.UILevel > 2)
{
string readme = io.Path.Combine(e.InstallDir, @"Docs\readme.txt");
if (io.File.Exists(readme))
Process.Start(readme);
else
MessageBox.Show("Readme.txt is not installed.\n"+
"You need to download it from the product website.",
e.ProductName);
}
}
Scheduling of AfterInstall is slightly different to the other two events. It is actually a deferred Custom Action. This means that it will always run elevated. This implies that the actual MSI session object (WixSharp.SetupEventArgs.Session
) is already closed and the MSI properties are no longer available (deferred actions limitation). But Wix# preserves the all important properties so they are still available for use. The WixSharp.SetupEventArgs.ToString
gives a good idea what session properties can be accesses even when they are already unavailable with the native MSI session object:
_Note that not all properties of are the SetupEventArgs
are populated by MSI runtime. This due to the fact that same of them are only available after the isntallation (e.g. session["Installed"]). _
When it comes to UI Wix# offers a few ways of simplifying development of MSI UI:
You can define an ordinary WinForm dialog and indicate when in the UI sequence MSI runtime should display it. This model is simple to use though it is somewhat limited as it dosn't allow to modify any of the standard UI dialogs.
Wix# provides a binding mechanism for integrating a standalone managed UI application with the MSI runtime. This is the most flexible UI development approach though it relies on the complex interop interface. The distribution model is a pair of the exe (UI application) and the msi file. Alternatively msi can be embedded into the exe and extracted upon the execution.
WiX/MSI also supports embedding an external UI directly into the msi file. Wix# makes embedding the UI as simple as a single line of code:
project.EmbeddedUI = new EmbeddedAssembly("<assembly path>");
. Embedded UI is nothing else but an External UI assembly stored in the MSI. The interop interface between the UI and MSI runtime is completely hidden within WiX abstraction layer. The distribution model is the same as with any MSI installation - a single msi file.
Wix# recognizes Embedded UI as a major API model and now it is a recommended way for any UI customization. Starting from v1.0.22.3 Wix# extends the Embedded UI model even further by reimplementing all standard MSI dialogs in C# (WinForms). It means that now UI can be as customizable as any .NET UI.
Wix# Standard Dialogs support is implemented as a main window shell stepping through the sequence of the user defined or standard dialogs and displaying a single dialog at the time:.
The easiest way of customizing the UI is to create the VS project from one of the Wix# VS templates:
The "Custom Dialog" template will create a project with an empty custom dialog already integrated in the UI sequence. You will only need to customize the dialog according your requirements.
The "Custom UI" project will create a project with the source code for all standard dialogs forming a typical standard MSI UI everyone is well familiar with. You will note that some of the usual UI features as (disk space estimation, countless confirmation message boxes, feature item context menus .etc) are completely omitted due to the low practical value. But should you require them (or any new feature) you can easily implement them by yourself. For example Wix# implements slightly different standard Exit Dialog. It allows an immediate inspection of the setup log file without restarting the *.msi/msiexec.exe with extra command line arguments:
When customizing UI it can be beneficial to be able to preview the dialog or the whole dialogs sequence without executing the actual msi. Wix# allows this by running UI dialogs in a demo-mode.
//play (run) whole install UI sequence
UIShell.Play(ManagedUI.Default.InstallDialogs);
//play (show) a single Exit dialog
UIShell.Play(Dialogs.Exit);
Of course by implementing your setup as a "Managed Setup" you are introducing a new dependency - CLR dependency. For quite some time it was a subject of some hot discussions in the "WiX house". Some believed that that any MSI setup should be native and 'pure', the way it was created in 1999. Others believed it should reflect and embrace the changes of the programming landscape introduced this century. For quite some time any integration of MSI runtime with CLR was only an experimental effort. But today CLR is a part of any Windows OS. Even the older versions of Windows are getting the CLR present thanks the system update policies. WiX eventually recognized that and now it comes with plenty of CLR dependant features. Thus the "war" is over (at least for majority of developers). It is no longer a question if it is OK to depend on CLR. The question is how to deal with this dependency.
The first step for handling dependency is to define a proper LaunchCondition (see 'LaunchConditions' sample):
project.SetNetFxPrerequisite("NETFRAMEWORK45 >= '#378389'",
"Please install .Net 4.5 First");
Though you can be even more proactive and bundle your application with the .NET setup (or a downloader/installer). The bundle (bootstrapper) doesn't even have to have it's own UI. You can make is silent thus it will only serve the purpose of automatically ensuring presence the required .NET version. The following code is a complete WixBootstrapper_NoUI sample from the Wix# suite:
var productProj =
new Project("My Product",
new Dir(@"%ProgramFiles%\My Company\My Product",
new File("readme.txt"))) { InstallScope = InstallScope.perUser };
productProj.GUID = new Guid("6f330b47-2577-43ad-9095-1861bb258777");
string productMsi = productProj.BuildMsi();
var bootstrapper =
new Bundle("My Product",
new PackageGroupRef("NetFx40Web"),
new MsiPackage(productMsi) { DisplayInternalUI = true });
bootstrapper.Version = new Version("1.0.0.0");
bootstrapper.UpgradeCode = new Guid("6f330b47-2577-43ad-9095-1861bb25889b");
bootstrapper.Application = new SilentBootstrapperApplication();
bootstrapper.Build();
And when it comes to the compatibility of the CLR required by your (or Wix#) assembly and the CLR present on the target system you can handle it the same way as with any managed assembly/application: via the app.config file. Read more about compatibility in this section.
- Home - Overview
- Architecture
- Documentation
- Samples Library
- Product Roadmap
- Tips'n'Tricks