Tuesday, November 23, 2004

Microsoft's Whitepaper on Patch Sequencing

While browsing, I came across this excellent whitepaper on MSI 3.0 Patch Sequencing.


http://www.microsoft.com/downloads/details.aspx?FamilyId=AD7AC91E-2493-4549-AE6F-BF5E007C12A3&displaylang=en

Using WIX Toolset for Distributed Development

When I talk to my fellow developers and other installation developers about the WIX Toolset, they do not fully understand the implications of the WIX Toolset in its own right but map its features to their favorite installation development tools. The WIX Toolset mostly ensures that you follow the best practices while authoring packages. The biggest advantage of the WIX Toolset over other applications is the support for distributed development. I have raved and ranted about this in my previous blog entries but I would substantiate it with actual WXS code this time. For starters, WXS file is an XML file that has to follow the schema as specified in the wix.xsd file in the 'doc' folder of your distribution. Rob has an excellent demo on distributed development with the WIX toolset. But the quality of video is very poor and the sample files are not yet available for us to tweak around with. So I have come up with my own example.

Let us assume the following scenario. There are group of installation and application developers in the organization working on a setup project. Let us allocate roles (purely hypothetical. I am not a manager <grin/>) for our convenience. Let us assume that the application developers take care of maintaining a catalog of components and resources that go into the product. The second developer takes care of assigning the appropriate components into the respective merge modules or features in a product. Let another developer be responsible for creating UIs. Additionally, each application developer creates his own fragments of files by hand or by using a simple tool. Let us assume that we have to package three files.


  1. Notepad.exe

  2. ReadMe.txt

  3. Calc.exe

Notepad.exe and Readme.txt are a logical unit and hence we would put them in a single component called Notepad.exe and set Notepad.exe as the key file of the component. We would also have Readme.txt as a companion file for Notepad.exe such that the versioning logic of Readme.txt is controlled by the versioning logic of Notepad.exe. Calc.exe is a standalone application that does not have anyother files. So here we go. The application developer codes his file named Dev1.wxs. Pretty simple isn't it?

<!--Dev1.wxs-->
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <Fragment>
    <DirectoryRef Id="INSTALLDIR">
      <Component Id="Notepad.exe" Guid="12CC008F-89A6-422d-868B-B066606FFD99" DiskId="1">
        <File Id="Notepad.exe" Name="Notepad.exe" LongName="Notepad.exe" KeyPath="yes" src="$(env.BUILDPATH)\Notepad.exe">
            <Shortcut Id="LaunchNotepad" Advertise="no" Description="Launches Notepad" Directory="DesktopFolder" Name="Notepad" LongName="Launch Notepad" WorkingDirectory="INSTALLDIR" Icon="Notepad.ico"/>
        </File>
        <File Id="Readme.txt" Name="Readme.txt" LongName="Readme.txt" CompanionFile="Notepad.exe" src="$(env.BUILDPATH)\Readme.txt"/>
      </Component>
    </DirectoryRef>
    <Icon Id="Notepad.ico" src="$(env.BUILDPATH)\Notepad.ico"/>
 
</Fragment>
</Wix>

Now the second application developer creates his file dev2.wxs.

 

<!--Dev2.wxs-->
<
Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <Fragment>
    <DirectoryRef Id="INSTALLDIR">
      <Component Id="Calc.exe" Guid="2C5ECB67-E585-4301-BAF4-5380FE6C26AB" DiskId="1">
        <File Id="Calc.exe" Name="Calc.exe" LongName="Calc.exe" KeyPath="yes" src="$(env.BUILDPATH)\Calc.exe"/>
      </Component>
    </DirectoryRef>
  </Fragment>
</Wix>

By now, the UI guy would have created a new WXS file for UI or stole the UI from a premade package. I normally steal UI from premade(I just coined this word) packages like Orca or some UI generated by freeware installers. Writing UI code for MSI using the WIX toolset is not exactly a pleasurable experience. <sigh/> So here goes the UI file. I am not going to include the WXS file here but if you need it, you can send me an email at vagmi.mudumbai@gmail.com. Now we have a file called dialogs.wxs which just has a bunch of dialogs, binaries, error texts, UITexts and properties defined for the UI.

Now we have to piece together each of these files and link them to our product. This is the MyProduct.wxs file which contains the feature-component mapping and the rest of the installation logic.

<!--MyProduct.wxs-->
<
Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
  <Product Id="148E08FF-D7C4-46ed-8D4D-601C67FE0AFD" Language="1033" Name="MyProduct" Version="1.0.0" UpgradeCode="B7FE793A-800D-4c14-8CB4-B00AA84FF685" Manufacturer="Vagmi">
    <Package Id="D1192FCD-BA01-4d8f-BA7B-663CE9934BDE" Compressed="yes" Description="My WIX Installation" InstallerVersion="200" Languages="1033" Manufacturer="Vagmi"/>
    <Media Cabinet="Data.cab" EmbedCab="yes" Id="1"/>
    <Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="ProgramFilesFolder" Name="PFiles">
            <Directory Id="INSTALLDIR" Name="Vagmi"/>
        </Directory>
        <Directory Id="DesktopFolder" Name="DTFOLDER"/>
    </Directory>
    <UI>
        <InstallUISequence>
            <Show Dialog="SetupCompleteError" OnExit="error" />
            <Show Dialog="SetupInterrupted" OnExit="cancel" />
            <Show Dialog="SetupCompleteSuccess" OnExit="success" />
            <Show Dialog="SetupInitialization" After="LaunchConditions" />
            <ResolveSource Before="CostFinalize"><![CDATA[Not Installed And Not PATCH]]></ResolveSource>
            <Show Dialog="InstallWelcome" After="MigrateFeatureStates"><![CDATA[Not Installed And (Not PATCH Or IS_MAJOR_UPGRADE)]]></Show>
            <Show Dialog="SetupResume" After="InstallWelcome"><![CDATA[Installed And (RESUME Or Preselected) And Not PATCH]]></Show>
            <Show Dialog="MaintenanceWelcome" After="SetupResume"><![CDATA[Installed And Not RESUME And Not Preselected And Not PATCH]]></Show>
            <Show Dialog="SetupProgress" After="MaintenanceWelcome" />
        </InstallUISequence>
    </UI>
    <Feature Id="TheOnlyFeature" ConfigurableDirectory="INSTALLDIR" Level="1" Title="TheOnlyFeature" Description="TheOnlyFeature">
        <ComponentRef Id="Notepad.exe"/>
        <ComponentRef Id="Calc.exe"/>
    </Feature>
  </Product>
</Wix>

As you can clearly see, the complex job of creating an installer package is split among the developers. This is a great feature as it does away with Merge Modules and all the associated hassles with modularization. Further changes or corrections can be made independently without affecting other parts of the installation. The only part that needs automation is the generation of WXS fragments for the developers. Although it is a simple piece of code to write, we cannot expect all developers to be conversant with XML and learn the WIX toolset. All we need is for them to specify the files and the destinations in a tool and a tool that should generate minimal WXS code for these fragments. I do not think that should be a problem considering the level of automation installation and build teams adopt for other tasks.

Building these is a straight forward task.


  • Compile the files using the following command.
    candle dev1.wxs dev2.wxs dialogs.wxs myproduct.wxs

    This would produce dev1.wixobj, dev2.wixobj, dialogs.wixobj and myproduct.wixobj

  • You can then link the generated object files using light.
    light -out build/product.msi dev1.wixobj dev2.wixobj dialogs.wixobj myproduct.wixobj

The myproduct.msi file would be generated in a folder named 'build' under the current directory.

Monday, November 22, 2004

WIX Tool

I have become quite lazy off late. I caught up with the WIX chat only after Rob posted the link on his blog. I was glad to find out that WIX was going to get integrated into Visual Studio.NET and there would be a MSBUILD task for WIX in Visual Studio .NET 2005. Very interesting indeed. Read the Windows Installer chat transcript for more information.


There has been a lot of commotion in the wix-users list about a good tool that generates WIX code for us. It was really encouraging to find out that there are a lot of developers just like me who feel that it is important to have a WIX code gen tool at least for the painful UI parts. Also it would help us get the overall view of the Setup project. I would visualize the tool to be some sort of a modeler than a full blown tool like InstallShield. I would still like to edit the XML code by hand and use the tool only as a layer to automate the redundant tasks. This would of course save a lot of time for more interesting things for more important stuff. (Yes. Gaming does count as one of the important stuff.) <smile/>


I am no C# guru and I really have started learning C# and .NET only for the past 6 months. Yeah! I have been a little slack in joining the .NET bandwagon. I have started coding in C# for fun and I have started to play around with the WIX code right about now. I have been trying to serialize and de-serialize WIX objects into XML contents using the Serialize namespace. But reality is just dawning on me. XML Serialization support in the System.XML namespace is not up to the mark. At least not up to my expectation. I spend most of my code type checking stuff and writing my own wrapper classes to expose the public members as properties. As I said, I am no tools guru but I was hoping to get each of the WIX object into the property grid. This would ease out most of the work and present a decent WXS reader if not a tool to write WXS file. Gabor has started working on a C# based WIX Dialog editor. I cant wait to get its sources. I am now looking for a good free refactoring plug in for Visual Studio .NET 2003 to convert public variables into public properties. I thought of writing the addin myself but I really don't want to re-invent the wheel. But if I end up writing it, I promise to expose the code to the community. <smile/>

Wednesday, November 03, 2004

Designing Good Setups

I have been mulling over the essentials of designing good setups and I found that most of it boils down to the component rules and the way you identify the data that goes to the setup. Microsoft enforces a set of rules that you should follow while authoring components. So, if the components are well managed, your product is well managed to a certain extent. Once you have identified the "Resources" in the setup, you would have to segregate them into components. Resources are bits installed by the setup, which do not change during the lifetime of the application, unless changed by a better version of the product by means of an MSI operation (small update/ minor upgrade/ major upgrade). Rob has blogged about what setup is and explains Resources, Application Data and User Data in good detail. I have my own opinions on handling application data. User Data is never installed, managed or removed and hence does not bother us.


Components are logical group of resources like Files, Registry entries, COM information, ODBC Data, Shortcuts and so on. Component is considered the atomic unit of installation. This statement is quite misleading and I have queued up a blog for Windows Installer's wierd behaviors to deal with that <grin/>.



  • As a rule of the thumb, you should place PE files (EXE, DLL, OCX and so on) individually in a component. Ensure that the key file that you select for a component is versioned. If the developer has not versioned the file, let him know that versioning a PE is very important to have a reliable upgrade. There are certain situations in which the setup developer has to assert his/her position to ensure the quality of the software shipped. After all if the installation fails, the customers would have no chance to further evaluate or use the product. If you have non-versioned resources that need to be upgraded, ensure that they are made companions to the key file of the component. This would ensure that the versioning logic for the component is consistent.

  • Never remove a resource or add a resouce to the component. If you have a file in the component, the only thing you can do is to bump up the file version or change the contents of the file itself. You can never add a file or remove a file from a component. This would result in incorrect reference counting and might prematurely remove resouces from the system or leave resource behind during uninstallation.

  • You cannot include resources going to multiple locations in the same component. Also you cannot change the destination of the component once declared. You would have to ensure that once the component design has been finialized, its destination's position in the directory product tree structure does not change.

  • If you have same file, especially a key file included in two different components that go to the same destination directory (e.g., 32 bit and 64 bit files or different language versions) ensure that these components are mutually exclusive by setting appropriate conditions on the components.

  • Component code and name of the component must be the same.

  • Make sure that there is only one COM server per component. Also ensure that the component is not linked to multiple features and is linked only to a single feature.

  • Ensure that shortcuts are included in the same component that has the file. Thus, the shortcuts are installed only when the file is installed. This might seem very elementary but people from other installation worlds like InstallScript, find this particularly hard to digest. 

Microsoft has also included a nice little article on things that could happen when component rules are broken in the Platform SDK.