Click here to Skip to main content
Click here to Skip to main content
Go to top

Wix# (WixSharp) UI Extensions

, 12 Sep 2014
Rate this:
Please Sign up or sign in to vote.
An article about UI extensions for WixSharp (C# interface to the WiX toolset)

Introduction

This article is a long awaited continuation of the Wix# development for the custom UI support. Even though the actual development was already complete for quite some time I was not able to adequately describe it until now. Despite my all effort my hectic schedule and various personal and professional commitments did not allow me to do so in a timely manner. Thus I do apologies for the delay as I am well aware about many Wix# users who patiently waited for the feature to arrive.

Please note that the article is not intended to be a tutorial or a product documentation but rather an analysis of the UI development options available with Wix#. Therefore if you are interested in the information on how to use Wix# please refer to the intensive samples library. The Wix# samples cover practically all possible deployment scenarios and they make ~95% of the total Wix# codebase volume. 

Background

Wix# was first released and described in this CodeProject article: Wix# (WixSharp) - managed interface for WiX.  

Wix# answers many MSI authoring challenges. It solves the common MSI/WiX authoring limitations in a very elegant and yet unorthodox way. Wix# follows the steps of other transcompilers like Script#, CoffeeScript or GWT by using source code of a more manageable syntax (C# in this case) to produce the desired source code of a less manageable syntax (WiX). A "more manageable syntax" in this context means less verbose and more readable code, better compile-time error checking and availability of more advanced tools.

Also Wix# removes necessity to develop MSI sub-modules (Custom Actions) in the completely different language (e.g. C++) by allowing both the components and behavior to be defined in the same language (C#). This also allows homogeneous, simplified and more consistent source code structure. 

Despite of all this there is one category of the setup authoring problems that Wix# didn't address so far: MSI custom UI. The reason for this is simple: the ideal setup should follow XCOPY paradigm and as such it should require very little (if any) customization of the deployment behavior that can be achieved only by the user interacting with UI elements. Thus it is preferred/recommended to have all application customization done on the first run of the product/application but not during the setup. 

However I have been asked by Wix# users about Custom UI support so many times that I could not longer ignore the demand and starting from v1.0.0 Wix# allows authoring MSI solutions with Custom UI. This covers the following scenarios:

  •     Defining custom WiX dialog.
  •     Defining custom CLR (WinForm) dialog.
  •     Building complete custom External UI (Console, WinForm or WPF)

The support for these three scenarios is representing three completely different MSI-related programming paradigms. These paradigms are not only different in terms of the internal design but also have a very different practical value and Developer Experience. Thus not all of these models are "equally recommended" or "practically useful". The detailed analysis of the differences and the final recommendations will be given in the Summary section.  

Custom UI support is the last big feature that completes Wix# as a product. Of course there will be defect fixes and improvements but I do not expect any major Wix# evolution. Among all the reasons for the move to "finalize" Wix# is a noticeable decline in the MSI relevance as a deployment technology. This is due to the gain of popularity of the alternative deployment solutions (e.g. ClickOnce) and the latest software trends associated with Windows and the all Microsoft technology stack all together. 

Custom UI with custom WiX dialog

This customization approach allows creating WiX custom dialogs. This is the most "orthodox" and at the same time least flexible approach.

Overview
WiX allows defining custom dialogs with the traditional WiX-XML syntax. Such dialog definitions are not intuitive, not readable, not maintainable and inconvenient to work with. The reason for this is not in WiX itself but in the convoluted nature of MSI.

In fact WiX team should be hailed for the effort of making dialog customization possible without bringing your brain to the boiling point.

MSI defines the runtime dialogs as a collection of the UI elements (e.g. labels, buttons) and stores them and their relationships in the dedicated tables (a table per UI element). The behavior associated with these UI elements is also stored in the multiple tables as Standard Actions (MSI built-in routines) and CustonActions (routines implemented in the external DLLs). On top of this the relations between dialogs (UI Sequence) are also stored in tables. The idea was that the developer would use Orcas (MSI DB editor) to modify the tables directly (row by row, field by field).

We need to remember that it was one of the first MS attempts to implement declarative application markup solution. Thus no wander that it was the clumsiest one. After MSI there were more successful solutions in this problem domain: MCE UI-markup, WPF/Silverlight, WinRT.

WiX has changed the game dramatically. It allowed defining UI elements, their relations and association with the behavior in the XML source code instead of "jumping" between the tables and fields.

Of course WiX could not address the fundamental flaws of the MSI model: external DLLs for behavior, convoluted nature of the UI elements relationships, limited number of the UI element types.

Though there is one area that could be improved within the WiX domain boundaries: 'visualization of the dialog definition at design time'. And this is what Wix# MSI Dialog support does. It allows using WinForm designer to define dialogs, which are to be converted in the WiX-XML definition at compile time. Most likely there some other visual designers for the MSI dialogs, though Wix# allows to do this by using the tools and the language we are all accustomed for (Visual Studio and C#). 

Thus to design a WiX dialog you will need to create a C# project and add a dialog inherited from WixForm class. Visual Studio will automatically associate the dialog source code with the WinForm designer and allow insertion of the WiX UI elements by means of the corresponding WixForm controls.

WixForm is a descendant of the System.Windows.Forms.Form and as such it has nothing to do with WiX/MSI and it cannot be directly instantiated by MSI runtime during the setup. Instead WixForm dialogs are destined for a "short life". WixForm dialogs are instantiated at compile time by the Wix# compiler and used to emit valid WiX-XML dialog layout definitions. The approach is fully consistent with the non-UI Wix#. Thus at compile time raw C# classes are translated to non-UI XML elements of the WiX source code and WixForms are translated to the XML definitions WiX UI dialogs.   

The following paragraphs illustrate the design of the Product Activation dialog:

The all samples in this section are from the CustomMSIDialog sample included in the latest Wix# distro. 

Runtime layout:

Fig1.

Source code:   

public partial class ProductActivationForm : WixForm
{ 
    public ProductActivationForm()
    {
        InitializeComponent();
    }
       ...

VS designer: 

Fig 2

WixForm support allows convenient editing of the dialog layout and the insertion of the predefined WixControls.

It is important to stress that MSI implements a very unusual UI model. All UI elements share the same set of attributes (properties). However only some of these attributes are really applicable to the element. For example the text UI element has all attributes of a check box and a list (e.g. CheckBoxValue or Sorted) while these properties are fully irrelevant for the nature of the text element. This mind bending model had to be fully followed by WiX. 

Wix# (WixForm) UI model is slightly more consistent with the traditional UI development.  WixButton for example exposes only relevant  properties (attributes) and hides all others.

Fig 3

While Wix# comes with only four the most common controls pre-defined: Button, Label, Textbox and Checkbox. The all other UI elements can be defined with the generic WixControl. For example the radio-button group on the  Fig 1/Fig 2 is defined as a WixControl with the "ControlType=RadioButtonGroup" and the EmbeddedXML as follow:

Fig 4

In fact it is possible to define any UI element available with MSI just by manipulating the ControlTypeEmbeddedXML and WixAttributes properties of the WixControl control. Thus for example WixChekBox is a specialized version of the WixControl control.

Apart from defining the dialog layout it is also necessary to inject the dialog in the UI sequence and to define the behavior associated with the dialog UI elements.
Making the dialog a part of the UI Sequence in WiX is normally done outside of the dialog definition. You can do this the same way as for any WiX project by placing the dialog XML definition and modifying the publish elements (UI elements actions) of the final WiX setup source. With Wix# you can accomplish this by handling the post-XML-generation event of the WixSharp.Compiler. You can generate the WiX-XML from a WixForm as follows:

var productActivationDialog = new ProductActivationForm();  //WixForm object  - WinForm

Dialog dialogDefinition = productActivationDialog.ToWDialog(); //Dialog definition - Wix# compiler instructions

XElement xml = dialogDefinition.ToXElement(); //WiX XML

Instead of injecting dialog XML and adjusting publish elements manually you can use Wix# to do this programmatically. Thus you can use built-in CustomUIBuilder.BuildPostLicenseDialogUI routine to directly convert productActivationDialog into WixSharp.Compiler instructions for generating WiX-XML. You can also use this routine to associate buttons UI events with the MSI Custom Actions.

project.CustomUI = CustomUIBuilder.BuildPostLicenseDialogUI(
                                      customDialog: productActivationDialog,
                                      onNextActions: new DialogAction[]{ 
                                                         new ExecueteCustomAction ("ValidateLicenceKey"),
                                                         new ShowDialog(Dialogs.InstallDirDlg, 
                                                                        "SERIALNUMBER_VALIDATED = \"TRUE\"")}); 
Compiler.BuildMsi(project);

The implementation of BuildPostLicenseDialogUI is relatively simple and if required it can be easily modified. Though you do not have to modify Wix# source code but instead you can implement your own customized routine. The sample CustomMSIDialog contains the example of such a routine: BuildCustomUI. This custom (user) routine is a full equivalent of the built-in BuildPostLicenseDialogUI.  

The sample also shows how button events can be associated with the actions directly in the button handler. The interesting thing is that the button event handler is never invoked by the pressing the dialog button as the dialog is never instantiated and only used by the Wix# compiler as a 'template' for the generating the dialog XML. However the compiler does invoke buttons handlers programmatically and this in turns emits necessary XML definition of the WiX button action. 

Conclusion
Wix# support for WiX dialogs allows building native XML dialog definitions. While using form designer dramatically simplifies editing of the dialog layout, defining the UI sequence and associating the actions with the UI elements inherits its complexity and unintuitive nature from the underlying WiX UI-related syntax.  

Wix# fully implements only 4 major UI controls but it allows defining all other control types with the generic WixControl. If required, you can easily define/implement any new UI control by deriving the new control from WixControl and properly initializing the control properties in the constructor. This way you can even implement your own library of the UI controls.

Custom UI with custom CLR dialog

This customization approach allows creating an ordinary WinForm dialog and displaying it during the installation. This is an extremely flexible approach as it allows unrestricted interaction with the user and OS fully unbound by the limitations of the WiX/MSI runtime limitations.

Overview
The concept is very simple. The plain-vanilla WinForm dialog with the layout, visually consistent with the typical MSI dialog, can be instantiated and displayed during the installation. The important aspect of this approach is that in the dialog you have the full power of .NET and C#. Thus in any of the WinForm events handlers you can perform any actions. The actions that are as complicated as you wish. Thus you can check the registry, or use WebClient to the product key on the license server, or to analyze the target OS, or start and stop multiple processes....

Wix# CLR dialog is just a Form inherited from WixCLRDialog.  
The all samples in this section are from the CustomCLRDialog sample included in the latest Wix# distro. 

Runtime layout:

Fig 5

Sourec code:

public partial class CustomDialog : WixCLRDialog 
{
    public CustomDialog(Session session) : base(session)
    {
        InitializeComponent();
        ...

VS designer:

Fig 6

At runtime you have access to the MSI session object, which in turne allows access to the all MSI resources. And from the buttons handler you can trigger three MIS navigation actions by calling one of the base class methods: MSIBack, MSINext or MSICancel.
The injecting the CLR dialog into UI Sequence is a similar to (but a bit simpler than) injecting the MSI dialog described in the previous section. You just need to inject the Custom Action in the "Next" button of the MSI dialog of your choice and display the CLR dialog from this action:

[CustomAction]  
public static ActionResult ShowProductActivationDialog(Session session)
{
    return WixCLRDialog.ShowAsMsiDialog(new CustomDialog(session));
}

Injecting the custom action can be done with the built-in InjectPostLicenseClrDialog:

var customDialogAction = new ShowClrDialogAction("ShowProductActivationDialog");
...
project.CustomUI = CustomUIBuilder.InjectPostLicenseClrDialog(customDialogAction.Id);

And if it is required the position in the UI sequence can be changed by implementing the equivalent of CustomUIBuilder.InjectPostLicenseClrDialog, which is a simple (~30 lines) routine to re-implement.

Conclusion
Wix# support for CLR dialogs allows building rich UI with unlimited UX possibilities. It also allows defining all MSI components: Custom Actions, UI and setup itself from the same codebase and with the same programming language. And this possibility is what it makes "Wix# + CLR dialogs" a true "all-rounder" in the cricket terms.
The only extra requirement imposed by using CLR dialogs is the requirement for the target OS to have .NET installed. Though it should not be a problem as for quite some time all versions of Windows come with .NET preinstalled.

External UI

The UI customization approaches described so far are following the MSI UI architecture. Both approaches offer a different level of the customization but in both cases it is achieved by injecting the custom dialogs without changing the concept of the MSI UI views sequence. 

Wix# though allows a completely different UI architecture. The architecture that can be achieved with a very low development effort and yet deliver an ultimate customization of the setup UI. Wix# implements very lean managed layer that selectively exposes MSI engine runtime API. Thus it is possible to implement fully isolated, self sufficient UI (with no MSI dependency) and "connect" it at runtime to the MSI engine running your MSI file. This approach isn't some sort of a trick or a work around. No, it is in fact the very original UI authoring approach of MSI that just been almost forgotten. Here is some background info.  

Background
The diagram below illustrates a typical MSI UI sequence, which corresponds to the UI built as per "Custom UI with custom CLR dialog" sample:

Fig 7

It all seems OK for the first look. One would think that the all dialogs are the "pages" that change each other in the application shell according the current setup step. However the problem is that there is no any application shell. The all dialogs are not the "pages" they are an individual windows that get created and destroyed (all in the same position on the screen) as user proceeds to the every next step.

What is even more puzzling is that dialogs and their non-navigational actions (Custom Actions) associated with the UI elements (e.g. buttons) belong to the different processes. This is hard to imagine but it is true. The UI is hosted by msiexec.exe abut all custom actions by various shortlived rundll32.exe instances. This convoluted UI architecture makes implementing the rich behavior or even custom interactions between the dialogs very difficult. Why MS chosen this design is a mystery. 

Though it is not the only option available. Thus MSI engine can be hosted by any application and the host application can trigger execution of the *.msi file, while providing it's own UI and fully handling the interaction with the user outside of the MSI engine. This rather straightforward architecture just makes sense. The host application provides the UI (of any complexity), collects the user input, loads and starts the msi file (initialized with the user input data) while indicating the progress. Such a monolith host/UI was not easy to implement with the technology available at the time when MSI was released. 

In 2000 I worked with an experimental MS framework for building MFC-based monolith UIs. The framework had some very good features but it didn't "stay around". Eventually MS decided to invest solely into the MSI-based fragmented UI. 

Today though the generic UI frameworks are way more advanced than 15 years ago. Thus it is only logical to introduce a framework for building the UI layer of the setup application without dependency on the MSI engine. UI layer that can be iplemented in any modern programming language/framework. And this is exactly what Wix# support for External UI is.

Overview
Wix# offers quite simple mechanism for executing the MSI file from any managed application. This is how you can run the MSI file from the console host application:
The all samples in this section are from the External_UI samples included in the latest Wix# distro. 

void RunSetup(string msiFile)
{
    var setup = new GenericSetup(msiFile, true);
    setup.ActionStarted += (s, e) => Console.WriteLine(setup.CurrentActionName);
 
    Console.WriteLine("The product is {0}INSTALLED\n\n", setup.IsCurrentlyInstalled ? "" : "NOT ");
 
    try
    {
        if (!setup.IsCurrentlyInstalled)
        {
            Console.WriteLine("Performing installation...\n");
            setup.ExecuteInstall(msiFile, "CUSTOM_UI=true");
        }
        else
        {
            Console.WriteLine("Performing uninstallation...\n");
            setup.ExecuteUninstall(msiFile);
        }
 
        Console.WriteLine("\nSetup is completed\n");
    }
    catch (Exception e)
    {
        Console.WriteLine("Error: {0};\nSee log file for details.\n", e.Message);
    }
 
    Process.Start(setup.LogFile);
}

From the diagram above (Fig 7) you can clearly see that UI has three distinctive runtime stages, associated with the well defined responsibilities:

  • Pre-Install stage: collect user input an pass it to the MSI engine as MSI property values.
  • Install stage: display the installation progress.
  • Post-Install stage: notify user about the install completion.

In the code sample the host application passes the MSI property values as the second parameter in the ExecuteInstall call. Installation progress notification is implemented as the setup.ActionStarted event handler and at the end of the setup the application prints the error/success message and opens the installation log file. 

The sample above only illustrates the simple installation use-case but the other samples (particularly WPFSetup) in the External_UI samples folder demonstrate the use of the more advanced features:

  • Merging MSI file into single self-sufficient host executable.
  • Enabling any combination of the MSI Features (groups installable components)  
  • Precise (percentage) progress indication
  • Detailed MSI logging
  • Various events:  OnStart, OnCompletion, OnError, OnProgressStep... 
  • Install/Uninstall/Repair
  • ...

Wix# shields the user from the all the complexity of the MSI API by providing a simple and natural interface for executing MSI files. The below is the diagram that illustrates the External UI architecture:

External_UI samples from the Wix# distributables contain three samples for three different host application types. 

Console Host (ConsoleSetup.csproj)
This is the simplest possible setup host application without the graphical UI but CLI instead.

 

WinForm Host (WinFormsSetup.csproj)
This is the simple setup host application with the WinForm single dialog UI.

WPF Host (WpfSetup.csproj)
This is the example of the setup host application with the rich WPF-based UI. 

What is also interesting is that now you can break away from the "conservative" page-mimicking MSI UI and build light single view UI with the progress indication like on the picture above. 


Conclusion

External UI is the most flexible development option for the developing rich UI for the MSI based deployment solutions. You can make your UI as rich as you want: you can use any UI elements, you can change the whole UX, you can use animations and so on. MS is using the same technique to implement dynamic interactive UI for their major products setups (e.g. Blend, Expression Web, Visual Studio,...). 

While there is nothing new in this approach, Wix# just makes it so much easier to implement it for the managed applications without going through the pain of Interop and an enormous (3000 lines) MSI API.

Acknowledgment

The Wix# External UI support implemented with Model Matter's MsiInterop solution available from https://github.com/jkuemerle/MsiInterop/blob/master/MsiInterop.cs.pp. It is a very well documented solution, which made the External UI support all possible.   

Summary

The Wix# UI Extensions deliver that last feature (UI support) that makes it now possible for Wix# to satisfy any deployment scenario. The described above three UI development use-cases MSI, CLR and External UI are very different in terms of the development effort and the final result. The following pros/cons overview will help you to make an intellegent choice of the UI authoring technique most appropriate for your deployment requirements.:

Custom MSI UI

Pros
- No dependency

Cons
- Limited variety of UI elements
- Follows the same overcomplicated MSI/WiX paradigm
- Requires understanding MSI/WiX layout markup
- Inadequate for implementing complex interaction scenarios
- Complex algorithms need to be implemented as Custom Actions
This approach is only suitable for very simple UI customization. Necessity to preserve user input in properties and inability to pass these properties to Custom Actions directly makes this approach potentially effort consuming. 

Custom CLR UI

Pros
- Unlimited variety of UI elements
- Standard well-known (WinForms) programming model  
- Low dependency on MSI/WiX layout markup
- Comfort of the first class programming language

Cons
- .NET dependency
- UI is heterogeneous: some dialogs are managed and some are native
This approach is suitable for any level of UI customization. The UI can be as complicated as any WinForms application. The only logical limitation is that the custom dialog appearance needs to be consistent with the standard MSI UI. 

External UI

Pros
- UI with no limitations at all
- Choice of any managed UI programming model: WinForms, WPF, Mono.GTK...  
- No dependency on MSI/WiX layout markup
- Comfort of the first class programming language
- Homogeneous UI

Cons
- CLR dependency
- Potentially can lead to the intensive development if the UI is too ambitions for the purpose. 
This approach is suitable for any level of UI customization. This is ultimately the most powerful and flexible approach. 

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Oleg Shilo
Technical Lead
Australia Australia
I was born in Ukraine. After completing the university degree worked there as a Research Chemist. Last 18 years I live in Australia where I've got my second qualification as a Software Engineer.
 
"I am the lucky one: I do enjoy what I am doing!"

Comments and Discussions

 
QuestionMany images... PinprofessionalRavi Bhavnani12-Sep-14 7:05 
AnswerRe: Many images... [modified] PinmemberOleg Shilo12-Sep-14 15:58 
GeneralRe: Many images... PinprofessionalRavi Bhavnani13-Sep-14 2:37 
GeneralRe: Many images... PinmemberOleg Shilo13-Sep-14 19:58 
GeneralMy vote of 5 PinprofessionalVolynsky Alex8-Aug-14 21:50 
GeneralRe: My vote of 5 PinmemberOleg Shilo8-Aug-14 22:14 
GeneralRe: My vote of 5 PinprofessionalVolynsky Alex9-Aug-14 2:03 
GeneralMy vote of 5 Pinmemberthund3rstruck7-Aug-14 7:25 
GeneralRe: My vote of 5 PinmemberOleg Shilo7-Aug-14 14:38 
GeneralGreat update PinmemberMember 109523967-Aug-14 1:52 
GeneralRe: Great update PinmemberOleg Shilo7-Aug-14 1:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 12 Sep 2014
Article Copyright 2014 by Oleg Shilo
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid