How To Generate Installer Using Wix#

Introduction

Wix# is an open Source framework available on GitHub and used for generating Installer using C# syntax. Wix# is an open source framework for building installer setup for MSI source code by using script file that is written into C#. Wix# uses C# to produce a wix or MSI source code. Using wix#, easily create a sample installer MSI file if familiar with C# syntax. The logic behind wix# uses C# syntax that updates .wxs file and generates MSI source code.

Background

Wix installer can be compiled into two MSI packages - one for 32-bit and the other for 64-bit.Windows Installer’s inability to write to the 64-bit Program Files directory from a 32-bit MSI package.

Features
  • Displays a license agreement
  • Checks to prevent installing the 32-bit version on a 64-bit OS
  • Uses the upgrade logic
  • Custom dialog
  • Puts an executable and a config file in %ProgramFiles%
  • Prevents multiple installations of the same product, etc.
Using the Code

First, create a sample .NET C# application using Visual Studio.

Then, you need to add wix# package from nuget manager.

 

There are different ways to create installer with custom dialog box we can modify, but we can start with the first simple MSI file.

Check out the online HTML CheatSheet here and save this link because you might need it while composing content for a web page.

  1. using WixSharp;  
  2.   
  3. namespace WixSharpSetup  
  4. {  
  5.     public class Program  
  6.     {  
  7.          private static void Main()  
  8.         {  
  9.                  var project = new ManagedProject  
  10.                                ("Sample.Installer",// your installer msi file name  
  11.                                new Dir  
  12.                                (@"%ProgramFiles%\Sample.Installer\Sample.Installer",//where   
  13.                                //files are extract in program files when installer run.  
  14.                                new File("Program.cs")));//which file   
  15.                                           // you want into include into installer.  
  16.                  project.GUID =   
  17.                  new Guid("52e30b47-2514-4114-9095-1861ba258814"); // Upgrade code   
  18.                  //HAS to be the same for all updates.Once you've chosen it don't change it.   
  19.                  project.ManagedUI = ManagedUI.Empty;    //no standard UI dialogs  
  20.                  project.ManagedUI = ManagedUI.Default;  //all standard UI dialogs  
  21.                  //custom set of standard UI dialogs  
  22.                  project.ManagedUI = new ManagedUI();  
  23.                  project.ManagedUI.InstallDialogs.Add(Dialogs.Welcome)  
  24.                                            .Add(Dialogs.Licence)  
  25.                                            .Add(Dialogs.SetupType)  
  26.                                            .Add(Dialogs.Features);  
  27.                  project.Load += Msi_Load; // generate event. occurs when ,.msi file load  
  28.         }  
  29.          private static void Msi_Load(SetupEventArgs e)  
  30.         {  
  31.             if (!e.IsUISupressed && !e.IsUninstalling)  
  32.                 MessageBox.Show(e.ToString(), "Load");  
  33.         }  
  34.     }  
  35. }  

Once you build your application, it will generate Sample.Installer.msi setup.

When you build your application, this .msi setup file generates on basedirectory.

Later, when you start installing, it looks like below:

 

Check OS compatibility for many more features that would be available to build installer easily.

Generate Shortcut 
  1. project.ResolveWildCards()  
  2.           .FindFile((f) =>  
  3.           f.Name.EndsWith("Sample.Installer.exe")).First()  
  4.           .Shortcuts = new[] {  
  5.                               new FileShortcut  
  6.                               ("Sample.Installer.exe""INSTALLDIR"),  
  7.                               new FileShortcut  
  8.                               ("Sample.Installer.exe""%Desktop%")  
  9.                          };  
  10.        // .ResolveWildCards() Used For  
  11.        //    Resolves all wild card specifications if any.  
  12.        //     This method is called by WixSharp.Compiler  
  13.        //     during the compilation. However it might be convenient  
  14.        //     to call it before the compilation if any files matching the  
  15.        //     wild card mask need to be handled in special way  
  16.        //     (e.g. shortcuts created). See  
  17.        //     WildCard Files example.  
  18.        //     WixSharp.Project.ResolveWildCards(System.Boolean)  
  19.        //     should be called only after WixSharp.WixProject.SourceBaseDir is set.  
  20.        //     Otherwise wild card paths may not be  
  21.        //     resolved correctly.  
Generate shortcuts of file "%Desktop%" generate shortcut on desktop.

Customize Licence Agreement

sing wix# also, you can specify your external .rtf license agreement file. 
  1. project.LicenceFile = "D://licence.rtf"; // Relative path  
  2.     //to RTF file with the custom licence agreement to be displayed in  
  3.     //the Licence dialog. If this value is not specified  
  4.     //the default WiX licence agreement will be used.  
Add Folders All Files into Installer .msi Setup File
  1. string path =   
  2. @"E:\Projects\SampleInstaller\CodeBase\Devlopment\Sample.Installer\bin\Release\*.*";  
  3. var project = new ManagedProject("Sample.Installer",  
  4.                           new Dir(@"%ProgramFiles%\Sample\Sample.Installer"  
  5.                           ,new Files(path) // include All files in Release Folder   
  6.                            ));  

Using Files class of Wix# library include folder all files. We can also specify condition for files we need to include into setup files for exa.

  1. string path =  
  2. @"E:\Projects\SampleInstaller\CodeBase\Devlopment\Sample.Installer\bin\Release\*.*";  
  3.   
  4. Predicate<string> condition =  
  5. new Predicate<string>(f => !f.EndsWith(".xml"));  
  6.   
  7. var data = new Files(path, condition);  
  8.   
  9.            var project = new ManagedProject("Sample.Installer",  
  10.                          new Dir(@"%ProgramFiles%\Sample\Sample.Installer"  
  11.                          , new Files(path, condition)  
  12.                              ));  

Specified condition for including all files except a particular condition in the above code includes all files in Release folder excluding XML files.

Check for .NET Framework Version for Installer
  1. project.SetNetFxPrerequisite  
  2. ("WIX_IS_NETFRAMEWORK_461_OR_LATER_INSTALLED >= '#394254'",  
  3.             "requires .NET Framework 4.6.1 or higher."); //Binds the  
  4.             // LaunchCondition to the version condition based on WiXNetFxExtension  
  5.                                                          //     properties.  
  6.                                                          //     The typical conditions are:  
  7.                                                          //     NETFRAMEWORK20='#1'  
  8.                                                          //     NETFRAMEWORK40FULL='#1'  
  9.                                                          //     NETFRAMEWORK35='#1'  
  10.                                                          //     NETFRAMEWORK30_SP_LEVEL  
  11.                                                          //     and NOT NETFRAMEWORK30_SP_LEVEL='#0'  
Validate Assembly Compatibility
  1. private static void ValidateAssemblyCompatibility()  
  2.        {  
  3.            var assembly = System.Reflection.Assembly.GetExecutingAssembly();  
  4.   
  5.            if (!assembly.ImageRuntimeVersion.StartsWith("v2."))  
  6.            {  
  7.                Console.WriteLine("Warning: assembly '{0}'  
  8.                is compiled for {1} runtime, which may not be compatible  
  9.                with the CLR version hosted by MSI. " +  
  10.                                  "The incompatibility is particularly  
  11.                                  possible for the EmbeddedUI scenarios. " +  
  12.                                   "The safest way to solve the problem  
  13.                                   is to compile the assembly for v3.5 Target Framework.",  
  14.                                   assembly.GetName().Name, assembly.ImageRuntimeVersion);  
  15.            }  
  16.        }  

In wix#, also provide Event when your installer loads, before loading and after. It will work for when Installer starts installing, before that call RestApi and check for some valid key and if it's true, only then will users allow install, otherwise not.

History
  • First release of code and article
I  have posted this article in CodeProject.com.