Thursday, May 3, 2012

WiX Research - Building Installer using WiX Sharp partially


Looking beyond WiX Sharp…

Here is another implementation of WiX as a part of on-going research. In the following implementation I have used few features of WiX Sharp and predominantly WiX to build an installer (.msi). This is unlike the previous implementation where I have user WiX Sharp only.

What is the requirement of further refining the implementation? 
And what is the requirement of moving away from WiX Sharp?

I see there are few shortcomings using WiX Sharp:
  • There is a dependency on third party tool (WiX Sharp) which may go against proprietary norms of the company.
  • There are many features implemented or can be tweaked in WiX as per user requirement; which may not possible if we are heavily dependent in WiX Sharp.
  • Having your own middle tier will give more control over your implementation.


Note :- I am really a fan of WiX Sharp and see value it has but on the other hand when thought of it rationally compelled me to look beyond WiX Sharp.

Salient features of the implementation:
  • Building .wxs file using WiX Sharp.
  • Integrating custom installation path using System.XML.LINQ.
  • Executing Candle.exe and Light.exe using System.Diagnostics.Process to build the installer.


Feedback are appreciated to improve implementation and if I am missing out anything.

ExeEXE – Standard function to call System.Diagnostics.Process to execute EXE and get the return value.

public bool ExeEXE(string sApplication, string sAppArgs)
{
    System.Diagnostics.Process AppProcess = new System.Diagnostics.Process();
    AppProcess.StartInfo.FileName = sApplication;
    AppProcess.StartInfo.Arguments = sAppArgs;
    AppProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    AppProcess.Start();
    AppProcess.WaitForExit();
    if (AppProcess.ExitCode > 0)
        Errorobj = "Error excounter while executing " + sApplication + " in " + this.ToString();
    else
        Errorobj = null;
    return (AppProcess.ExitCode == 0) ? true : false;
}

InsertCustomPath – This function insert Custom action in .wxs file for assigning custom path

private void InsertCustomPath()
{
    XDocument Doc = XDocument.Load(Environment.CurrentDirectory + @"\Test Product.wxs");
    if (Doc.Root != null)
    {
        XNamespace xNS = Doc.Root.GetDefaultNamespace();
        XElement xCustAct = new XElement(xNS + "CustomAction",
                                         new XAttribute("Id", "CustActSetINSTALLDIR"),
                                         new XAttribute("Return", "check"),
                                         new XAttribute("Execute", "firstSequence"),
                                         new XAttribute("Property", "TARGETDIR"),
                                         new XAttribute("Value", sInstDir));
        XElement xUI = new XElement(xNS + "UI",
                                    new XElement(xNS + "InstallUISequence",
                                                 new XElement(xNS + "Custom",
                                                              new XAttribute("Action", "CustActSetINSTALLDIR"),
                                                              new XAttribute("After", "ValidateProductID"), "TARGETDIR=\"\"")));
        XElement xExeSeq = new XElement(xNS + "InstallExecuteSequence",
                                        new XElement(xNS + "Custom",
                                                     new XAttribute("Action", "CustActSetINSTALLDIR"),
                                                     new XAttribute("After", "ValidateProductID"), "TARGETDIR=\"\""));
        XNode Node = Doc.Root.FirstNode;
        while (Node != null)
        {
            if (((XElement)Node).Name.LocalName == "Product")
            {
                XNode ChildNode = ((XElement)Node).FirstNode;
                while (ChildNode != null)
                {
                    if (((XElement)ChildNode).Name.LocalName == "Directory")
                    {
                        ChildNode.AddAfterSelf(xCustAct);
                    }
                    else if (((XElement)ChildNode).Name.LocalName == "Upgrade")
                    {
                        ChildNode.AddAfterSelf(xExeSeq);
                        ChildNode.AddAfterSelf(xUI);
                    }
                    ChildNode = ChildNode.NextNode;
                }
            }
            Node = Node.NextNode;
        }
    }
    Doc.Save(Environment.CurrentDirectory + @"\Test Product.wxs");
}

BuildInstaller – Main function to build .wxs and then execute Candle.exe and Light.exe.

public object BuildInstaller()
{
    try
    {
        WixEntity[] weDir1 = new WixEntity[0];
        weDir1 = BuildDirInfo(sRootDir, weDir1); // Implementation already been described in previous post
        var project = new Project("Test Product", new Dir("Test Product", weDir1))
        {
            GUID = Guid.NewGuid(),
            UI = WUI.WixUI_InstallDir,
            Manufacturer = "Test Company",
            Version = new Version(1, 1, 1, 0),
            LicenceFile = Directory.GetCurrentDirectory() + @"\EULA.rtf",
            BannerImage = Directory.GetCurrentDirectory() + @"\Banner.bmp",
            BackgroundImage = Directory.GetCurrentDirectory() + @"\Background.bmp",
            UpgradeCode = guidUpgradeCode,
            MajorUpgradeStrategy = new MajorUpgradeStrategy
            {
                UpgradeVersions = VersionRange.OlderThanThis,
                PreventDowngradingVersions = VersionRange.NewerThanThis,
                NewerProductInstalledErrorMessage = "Newer version already installed"
            }
        };
        
        // Building .wxs file using WixSharp.dll
        Compiler.BuildWxs(project, Environment.CurrentDirectory + @"\Test Product.wxs");
        
        InsertCustomPath();// Inserting Custom action for setting custom installation path
        
        //Executing Candle.exe and Light.exe using System.Diagnostics.Process
        string sCommandLine = "\"" + Environment.CurrentDirectory + "\\Test Product.wxs\" -out \"" + Environment.CurrentDirectory + "\\Test Product.wixobj\"";
        if (ExeEXE(Environment.CurrentDirectory + @"\wixbin\bin\Candle.exe", sCommandLine))
        {
            System.IO.File.Delete(Environment.CurrentDirectory + "\\Test Product.wxs");
            sCommandLine = "\"" + Environment.CurrentDirectory + "\\Test Product.wixobj\" -ext WixUIExtension -out \"" + sInstLoc + "\\Test Product.msi\"";
            if (!ExeEXE(Environment.CurrentDirectory + @"\wixbin\bin\Light.exe", sCommandLine))
            {
                obRtn = "ERROR: " + (string)Errorobj;
                return obRtn;
            }
            System.IO.File.Delete(Environment.CurrentDirectory + "\\Test Product.wixobj");
            System.IO.File.Delete(sInstLoc + "\\Test Product.wixpdb");
        }
        else
        {
            obRtn = "ERROR: " + (string)Errorobj;
            return obRtn;
        }
        return obRtn;
    }
    catch (Exception w)
    {
        MessageBox.Show(w.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    return null;
}

No comments:

Post a Comment