Using C # and Wix # to create msi packages

Original author: Jonathan Allen
  • Transfer
From a translator: English-speaking it-bloggers usually start such articles with the words I'm so excited. I found out about Wix # quite by accident and I hasten to share this discovery with the habrasociety, as Anyone who has been dealing with bare WiX knows how unpleasant this process can be. And now you can make the msi distribution by writing just a few lines in C #! I think it's awesome! And relatively recently (Dec 4, 2014) Wix # author Oleg Shilo gave an interview to InfoQ. I present the translation of this interview to your attention. And I ask you not to judge strictly for the tracing-paper of some words - the same “deployment” is somehow closer to me than “deployment”.


InfoQ: For those of our readers who have not heard of Wix #: what is it?

Oleg: Wix # (WixSharp) is a deployment authoring framework based on the Windows Installer (MSI). Wix # allows you to build a full-fledged MSI distribution according to a specification written in C #. A typical Wix # source file consists of regular C # code that uses C # classes to define WiX entities.

Wix # solves many problems when creating MSI. In an elegant and original manner, it circumvents the typical MSI / WiX limitations. Wix # followed by other transcompilers ( transcompilers) like Script #, CoffeeScript, or GWT uses source code in a syntactically more convenient language (in this case, C #) to get source code in a less convenient language (WiX). “Syntactically more convenient” in this case means less redundant and more readable code. Code in which there are more checks at the compilation stage and for which more advanced tools are available.

Wix # also removes the need to create MSI submodules (Custom Actions) in a completely different language (for example, C ++), allowing both components and behavior to be described in one language (C #). It also makes it possible to have a more uniform, simple and consistent source code structure.

But more importantly, Wix # provides an abstraction layer that hides the complexity and unintuitiveness of MSI / WiX and allows you to express the deployment algorithm in a more natural way. The code below is a typical Wix # example that demonstrates a script to create an .msi file to install the My App application:

using System;
using WixSharp;
class Script
{
    static public void Main()
    {
        var project = new Project("My App",
                          new Dir(@"%ProgramFiles%\My Company\My App",
                              new File(@"\\BuildServer\LatestRelease\Bin\MyApp.exe"),
                              new File(@"\\BuildServer\LatestRelease\Bin\MyApp.exe.config"),
                              new File(@"\\BuildServer\LatestRelease\Docs\readme.txt")));
        project.GUID = new Guid("6f330b47-2577-43ad-9095-1861ba25889b");
        Compiler.BuildMsi(project);
    }
}

Of course, Wix # can execute even more complex scripts (Custom Actions or even its own UI on WPF or WinForms), but the code above is a great example of what its essence is.

Wix # is part of the CS-Script utility suite: an open source scripting engine for executing C # scripts. InfoQ readers may already be familiar with it, as I already talked about it in my previous interview about the CS-Script plugin for Notepad ++.

InfoQ: Why did you choose the API format for Wix # rather than the domain specific language (DSL) format?

Oleg: The goal of Wix # is not to replace the XML syntax with some other. This would solve only one of the many practical limitations of the MSI + WiX bundle. With Wix #, I wanted to reduce the development of deployment to regular programming. I wanted the most ordinary developer who creates software to be able to quickly and comfortably create a deployment solution. DSL would mean that developers need to learn the next syntax and suffer from a lack of helper utilities such as Intellisense. Also, DSL would most likely require a separate language to create Custom Actions. I wanted C # and your favorite development environment (IDE) to become a “one-stop-shop” for developing a deployment. And then your team doesn’t need a separate WiX specialist,

However, there is a less obvious motive for abandoning the DSL approach. A typical DSL task is to translate one syntax into another or convert one software model to another. The translation task in the context of WiX has very little practical meaning. Despite the ease of implementation, this only translates the WiX syntax into a simpler one, but retains all the limitations of MSI. Conversely, transforming into a new cleaner and more intuitive programming model is exactly what WiX needs. Such a conversion is usually achieved using high-level general-purpose programming languages ​​(C # in the context of Wix #). And after that, the new programming model is usually tied to the new DSL syntax. However, in the case of Wix #, the last step (syntax binding) is not useful. The vast majority of Windows developers are quite comfortable or at least familiar with .Net languages. So the new DSL syntax would only bring extra overhead. So I decided to stop at C #.

Notwithstanding the foregoing, DSL on top of the Wix # software model can make sense and is easy to implement. But this is a completely different story ...

InfoQ: Besides the complexity of the format, what do you think is the biggest obstacle to adopting WiX?

Oleg : A very good question. Yes, WiX is really very complex, but the real obstacle is not complexity, but close communication with MSI. WiX dramatically simplifies access to the MSI programming model. However, this model itself, and not the complexity of access to it, is the root of the problem. So WiX users are still dealing with the inconvenience of MSI, only now using XML.

Here I would like to interrupt and say a few words in defense of WiX. The imperfect MSI software model is not WiX's fault. In fact, given thatWiX made for MSI, it is almost impossible to expect from him to fix the limitations of MSI. To truly appreciate WiX, we need to look back at the development of Microsoft deployment technologies.

When the MSI was introduced, it tried to be the "answer to all the questions." And, like many Microsoft technologies, it was overly complicated from the start. Since then, he has not changed. Microsoft implemented in MSI many complex functions that today have very little practical value (for example, components, MSM, advertising installation ...).

And there is nothing surprising in the fact that Microsoft realized the problem and got rid of all these features in their last attempt - ClickOnce. ClickOnce is a very simple deployment framework. In fact, Microsoft completely abandoned the MSI concept and implemented ClickOnce from scratch as an alternative. It is lightweight, smart and minimalistic (in a good way). True, it is more closed, not expandable and not customizable.

Due to internal flaws, MSI is extremely development friendly. An .msi file is a database file. Deployment logic is defined through data in tables. Microsoft suggested that MSI would be created by manually populating this data, field by field, using their Orca MSI table editor. This provided InstallShield a huge income (by raising the price of MSI support), but left developers with nothing. And then WiX happened. And he stopped the "chaos of MSI." WiX absolutely deserves all the praise for bringing order and making MSI creating a software development task (rather than driving in data) - “building binary files from source”. Thus, WiX allowed you to populate these MSI tables using an XML file, rather than manually. However, this did not change the essence of MSI development.

Just a couple of weeks ago, one of the WiX # users shared his solution for a simple MSI scenario, when you only need to make changes to the registry. The problem is that MSI / WiX requires you to set the installation folder ... even if you do not put a single file, but just enter the keys into the registry. The solution is to specify a dummy folder and then ... delete the folder operation in order to avoid physically creating the folder during installation. All this is necessary not because of deployment requirements, but because of the inexplicable limitation of MSI: the folder table must have at least one entry.

WiX #, on the other hand, allows you to automatically create an entry for a stub folder and completely hides the complexity of MSI / WiX:
var project = new Project("MyProduct",
                  new RegValue(RegistryHive.LocalMachine, "Software\\My Company\\My Product", "Message", "Hello"),
                  new RegValue(RegistryHive.LocalMachine, "Software\\My Company\\My Product", "Count", 777)); 
project.GUID = new Guid("6f330b47-2577-43ad-9095-1861ba25889b"); 
Compiler.BuildMsi(project);


The WiX equivalent of the code above will be about 40 lines of very dense XML code plus a batch file to launch the WiX compiler and linker.

A dummy folder is not an isolated case. There are many other syntactic "obstacles" to MSI / WiX that are resolved in Wix #.

Many WiX gurus believe that such proximity to the MSI architecture is the power of WiX because it gives absolute access to MSI functionality. I disagree. I am sure that this impedes the adoption of the whole technology, as it ignores the needs of the developer. Thus, WiX is fully MSI-oriented instead of being developer-oriented. But we should not blame WiX for this. I'm not even sure WiX should think about this at all. In my opinion, here we need another layer that would take the requirements / specification (for example, Wix # -file) and convert it to MSI-DB specification (WiX-file).

WiX plays the same role in the MSI environment as IL does in .NET. IL gives absolute access to CLR capabilities, but no one uses it for development. For this, we have all the high-level .NET languages. So if I rephrase the question as “what is the biggest obstacle to accepting IL?”, The answer will be simple. There is no need for acceptance. For development, we have options much better than IL (despite the fact that IL is a vital part of all .NET technology). And Wix # is an attempt to bring at least one of these “best options” into the MSI domain. So Wix # or any such solution is just the next development step after WiX.

InfoQ: Besides facilitating the creation of basic installation packages, what do you see as the most interesting feature of WiX #?

Oleg: There are some very important things worth mentioning.

1. First of all, this is the indestructible simplicity of managed (Custom) Custom Actions, which stems from the power of a high-level programming language (C #):
using System;
using WixSharp;
class Script
{
    static void Main()
    {
        var project = new Project("CustomActionTest",
                           new ManagedAction("MyAction", Return.check, 
                                             When.After, Step.InstallInitialize, Condition.NOT_Installed));
        Compiler.BuildMsi(project);
    }
}
public class CustomActions
{
    [CustomAction]
    public static ActionResult MyAction(Session session)
    {
        MessageBox.Show("Hello World!", "Embedded Managed CA");
        session.Log("Begin MyAction Hello World");
        return ActionResult.Success;
    }
}


2. Your UI. Wix # not only allows you to insert a regular WinForms dialog into the UI sequence. It also makes it possible to create your own GUI completely and slip it into the MSI engine runtime. This fantastic feature offered by the MSI API is completely overlooked by almost all MSI creation frameworks, despite the fact that Microsoft uses it in many of its products (in particular, the installers Office, Visual Studio).

I consider my own UI a very controversial deployment technique and do not advise (for design reasons) developers to go this way. But I just could not ignore user requests and still implemented it. Below is a screenshot of a WPF example (from the Wix # distribution) for its own UI:
image

3. The last feature I would like to mention is the extensibility of Wix #. The deployment description is just a declaration of the C # classes. It can be easily improved using its helper classes to simplify or modify normal installation conditions. For example, instead of listing all the files, you can create a class (for example, AllFiles) that will run through the folder structure and do it dynamically for you. So the installation script will not need to be changed when you need to include a new dll in the distribution package:
var project = new Project("My App",
                  new Dir(@"%ProgramFiles%\My Company\My App",
                      new AllFiles(@"\\BuildServer\LatestRelease\*.*")));


In the case where the capabilities of Wix # are not enough, you can directly work with the generated XML (WiX) content using the Wix # compiler event handlers (right before the XML is passed to the MSI compiler). You can add or remove any element or attribute from the XML tree. The examples show how to install an ASP.NET site using the built-in WiX # functionality and how to do the same by inserting the required XML right before compilation.

By the way, the number of examples in the Wix # distribution is so significant that it is ~ 95% of all Wix # code.

I believe that at this stage of the Wix # life cycle, its main functionality is almost complete. So new opportunities will provide more horizontal development than vertical. They will mainly focus on integration with development tools and the greater usability of the framework for developers. I plan to publish Wix # in NuGet ( done , approx. Transl. ), Provide the full equivalent of the MSI user interface, but as an external set of WinForm dialogs, develop a separate plug-in for Notepad ++ and, possibly, MSBuild tasks with the project template (at the moment) Visual Studio treats Wix # as a regular C # project). And, of course, processing user requests.

Wix # is available on CodePlex under the MIT license.

Also popular now: