Showing posts with label windows installer. Show all posts
Showing posts with label windows installer. Show all posts

Friday, May 10, 2013

WiX woes: What is your installer doing?

Summary: How to detect different modes of installation.
When building an application installer, it's often necessary to distinguish between different modes of installation, i.e. initial installation, repair, upgrade, uninstall, etc. And as with everything important in MSI, detecting the mode of installation is a PITA (and by PITA, I do not mean flat bread of Mediterranean origin). To help you a little bit, here is a table adopted from a StackOverflow topic (and comments), that shows the values of various Windows Installer properties can help you determine the installation mode:

Install Uninstall Repair Modify Upgrade
INSTALLED FALSE TRUE FALSE TRUE TRUE
REINSTALL TRUE FALSE TRUE FALSE FALSE
REMOVE="ALL" FALSE TRUE FALSE TRUE TRUE
UPGRADINGPRODUCTCODE TRUE FALSE TRUE TRUE TRUE

You can use logical operators NOT, AND, OR to build complex conditions.

Here is how you can detect some common conditions:

First-time installation
  • NOT Installed
Any installation
  • NOT Installed AND NOT PATCH
Installation and repairs
  • NOT REMOVE
First-time installation and repairs
  • NOT Installed OR MaintenanceMode="Modify"
Upgrades only (during uninstall phase)
  • Installed AND UPGRADINGPRODUCTCODE
Upgrades
  • Installed AND NOT REMOVE
Full uninstall (except when triggered by a major upgrade)
  • (REMOVE="ALL") AND (NOT UPGRADINGPRODUCTCODE)
Any uninstall
  • REMOVE~="ALL"
If you notice errors or want to include some other conditions, please post a comment.

See also:
MSI Property Patterns: Upgrading, FirstInstall and Maintenance
Upgrading, FreshInstall, Maintenance and other MSI convenience properties
MSI Writing Guidelines: Installation Scenarios
How to execute custom action only in install (not uninstall)

Thursday, May 26, 2011

Build 32- and 64-bit installers using WiX

Summary: Code samples illustrating how to build deployment packages for both x86 and x64 platforms from the same Windows Installer XML (WiX) project.
This is post #6 of the six-part Learning WiX series. For other topics, see:

Table of contents
  1. Background (why WiX?)
  2. Introduction (answers to common questions)
  3. Getting started (references and tutorials)
  4. How-to's and missing links
  5. Slides and demo projects
  6. Improved demo projects (32- and 64-bit installers)
My recent post offers code samples illustrating a life cycle and core features of a WiX deployment project. The samples miss one important aspect: target platforms (i.e. x86 vs x64). While the samples get installed and run fine on both 64-bit and 32-bit platforms, the deployed applications always appear as 32-bit programs, even though they run as 64-bit processes on 64-bit machines (all assemblies are compiled to run on Any CPU).

I tried to add 64-bit support to the existing projects, but ran into several issues (e.g. folder selection wizard always showed the wrong Program Files folder on 64-bit systems). It took me a few weeks to resolve the problems, so here are the updated projects (all projects use Visual Studio 2010):
These samples do everything the original samples do, plus:
  • Solutions include build targets for 64-bit platforms: Debug (x64) and Release (x64).
  • WiX projects can build 64-bit MSI files (via 64-bit build targets).
  • Build process renames MSI files to indicate target platforms and copies them to a separate MSI folder under the WiX project (in a post-build event).
  • Detect and use the original application folder during upgrades.
Here is what you need to do to build installers for 32- and 64-bit platforms:
  • Understand the differences between 32- and 64-bit installers.
    At the very least, you need to understand that a setup package (MSI file) file can be marked as either a 32- or 64-bit installer (64-bit installer cannot run on 32-bit systems, but it can install 32-bit components on 64-bit systems). The following article can give you a basic idea of intricacies related to 64-bit platform deployment: How Windows Installer Processes Packages on 64-bit Windows (see also other relevant articles).

  • Add the x64 build target to your WiX setup project.
    Assuming that all application assemblies (and support files) are not platform-specific, keep their build configuration marked as Any CPU, but add new configurations to the WiX setup project and associate it with the x64 platform; make sure configuration names identify the 64-bit platform, e.g. Debug (x64) and Release (x64).

    Tip: I often run into problems adding a new configuration via Visual Studio IDE. E.g. sometimes, I cannot add the x64 platform to some projects, or I would add it, but when I close the Configuration Manager dialog box, my settings would disappear. If you run into such issues, I suggest making changes directly to the project (.wixproj) and solution (.sln) files (their structure should be obvious). [Notice that you can edit a project file directly in the Visual Studio IDE by unloading and reloading the project.] Then open the Configuration Manager dialog box (via the Build - Configuration Manager menu), and make sure your project build mappings looks right.
    Your configuration settings should look similar to this:

    The idea here is that you always build your platform-independent assemblies for Any CPU and only use x86 and x64 targets for the setup projects (or any platform-specific project).

  • Define and use platform-specific properties in the WiX source (.wxs) file.
    It's a good idea to have platform-specific GUIDs for product ID and upgrade code, as well as product name. You should always use a variable to store platform-specific Win64 flag and folder names (such as Program Files folder). Here is the code that illustrates how to achieve this:
    <?define ProductName = "WiX Demo" ?>
    <?define ProductVersion = "1.0" ?>
    <?define ProductFullVersion = "1.0.0.0" ?>
    <?define ProductAuthor = "Alek Davis" ?>
    <?define ProductAppFolder = "InstallLocation" ?>
    
    <?if $(var.Platform) = x64 ?>
      <?define ProductDisplayName = "$(var.ProductName) 64-bit" ?>
      <?define ProductId = "47861F89-765F-4D6D-BEDE-139F0BCD74ED" ?>
      <?define ProductUpgradeCode = "EE2511C1-75A7-4954-8AB6-0E405C9481B4" ?>
      <?define Win64 = "yes" ?>
      <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
    <?else ?>
      <?define ProductDisplayName = "$(var.ProductName)" ?>
      <?define ProductId = "490CCCF1-54C3-4AC2-8C88-A8903556EEB3" ?>
      <?define ProductUpgradeCode = "E7E6A7CB-1D12-486D-9E53-DBC56B0EDDCB" ?>
      <?define Win64 = "no" ?>
      <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
    <?endif ?>
    The code above tells the WiX compiler to check the value of the build platform property $(var.Platform). If the compiler detects the x64 build platform target, it will set platform-dependent variables to 64-bit specific values; otherwise, it'll use 32-bit values.

  • Use platform-specific properties to set element attributes.
    Now you can use platform-specific properties set by WiX compiler instead of hard-coded values:
    <Product 
      Id="$(var.ProductId)" 
      Name="$(var.ProductDisplayName) (v$(var.ProductVersion))" 
      Language="1033" 
      Version="$(var.ProductFullVersion)" 
      Manufacturer="$(var.ProductAuthor)"
      UpgradeCode="$(var.ProductUpgradeCode)">
    
      <Package 
        InstallerVersion="300" 
        Compressed="yes" 
        InstallScope="perMachine" 
        Manufacturer="$(var.ProductAuthor)" 
        Platform="$(var.Platform)" />
      ...
      <Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="$(var.PlatformProgramFilesFolder)" >
          <Directory Id="APPLICATIONFOLDER" Name="$(var.ProductName)"/>
        </Directory>
      ...
      </Directory>
      ...
    </Product>
  • Set platform flag on components.
    Make sure that all of your product components are marked with the appropriate Win64 flag. Use a variable (like $(var.Win64) defined in the code sample above) to change the value dynamically based on the build platform, such as:
    <Component
      ... 
      Win64="$(var.Win64)">
      ...
    </Component>
    If you have components which must be deployed only on 32- or 64-bit platform, you can hard-code their Win64 attribute values and conditionally include or exclude them based on the build target:
    <?if $(var.Platform) = x64 ?>
      <!-- 64-bit components go here -->
    <?else ?>
      <!-- 32-bit components go here -->
    <?endif ?>
  • Rename MSI files to indicate target platform.
    You can define a post-build step to rename your MSI files, so that they reflect the intended platform. Select the Project - Properties menu; in the Build Events tab, set the Post-build Event Command Line to something like this:
    if not exist "$(ProjectDir)msi" mkdir  "$(ProjectDir)msi"
    copy "!(TargetPath)" "$(ProjectDir)msi\$(TargetName)($(PlatformName))$(TargetExt)" /Y /V
    These commands rename and copy the output MSI file to the MSI folder (in the project directory). They will create the folder if it does not exist. The file name will contain the (x86) or (x64) suffix depending in the target platform (e.g. WixDemo1.0(x64).msi).
That's about it. Oh, almost forgot: test, test, test...

See also:
Walking through the creation of a complex installer package by Gabriel Schenker

Wednesday, March 2, 2011

Beginner’s guide to Windows Installer XML (WiX) 3.5

Summary: Slides and demo projects.
This is post #5 of the six-part Learning WiX series. For other topics, see:

Table of contents
  1. Background (why WiX?)
  2. Introduction (answers to common questions)
  3. Getting started (references and tutorials)
  4. How-to's and missing links
  5. Slides and demo projects
  6. Improved demo projects (32- and 64-bit installers)
I just updated and uploaded the slides from the presentation I gave to my work group yesterday (you can download the PowerPoint [PPTX] presentation from the SlideShare site):

You can also download the demo projects.

There are three demo solutions, each containing four projects, all implemented in Visual Studio 2010 (you also need WiX 3.5 Toolset/Votive):
  • A client (Windows Forms) application.
  • A server (Windows service) application.
  • A class library (DLL used by both client and server).
  • A WiX 3.5 setup project handling deployment of the client, server, and class library.
The demo apps (client, server, library) don't do much (they are there only for the WiX project). The WiX setup project illustrates how to accomplish the following:
  • Install and configure a Windows service.
  • Install a client application.
  • Install a class library in Global Assembly Cache (GAC).
  • Install a text (readme.txt) file.
  • Create shortcuts under the Start menu for the client app and text file.
  • Create a shortcut under the Start menu for the application uninstaller.
  • Display the advanced setup dialog sequence (wizards) allowing the user to select the installation scope (per user or per machine), specify product destination folder, chose which features to install (client, server, or both).
  • Perform major upgrades (upgrades will retain Windows service definition for the already installed server component).
  • Include application files in the setup package via project references (instead of hard coding the file names).
The three solutions illustrate a typical life cycle of a project. First, you build and deploy version 1.0. Then you can build and deploy version 1.5. The version 1.5 installer will upgrade the already installed version (you don't need to uninstall version 1.0 before installing version 1.5). Then you can do the same for version 2.0. Notice that installers preserve Windows service configuration during upgrades (if you redefine the service to run as a specific user instead of a local system account, the service configuration will remain intact).

UPDATE: See new and improved samples, which explain how to implement installers for 32- and 64-bit targets and do other things.
I'd also like to recommend two books which I found extremely helpful: WiX: A Developer's Guide to Windows Installer XML by Nick Ramirez covers WiX; The Definitive Guide to Windows Installer (Expert's Voice in Net) by Phil Wilson - general Windows Installer (MSI) concept:


And one more thank you to Jeffrey Sharp for his excellent WiX presentation (you can get the slides and watch Jeff's talk online).

See also:
My three-part introduction to WiX series

Tuesday, October 19, 2010

How to fix a hanging uninstaller

Summary: How to fix a hung uninstaller issue due to inclusion of Visual C or MFC runtime merge module in the MSI package.
I have hassled with this problem for a long time and just recently figured out how to fix it, so I'm posting the solution in hope that it will help someone else.

Symptoms
You create an MSI package using Visual Studio, WiX Toolset, or whatever. The MSI package works fine during initial installations, repairs, and upgrades, but it takes really long time to uninstall. It may take two minutes, five minutes, 15 minutes, or longer, when it should've taken a few seconds. In my last case, after 20 minutes of waiting I gave up and killed the MSIEXEC process (this was during testing, so no harm was done).

Troubleshooting
I suspect that an uninstaller can (appear to) hang for different reasons. If your setup package includes merge modules for any version of Visual C or MFC runtime, such as Microsoft_VC80_CRT_x86.msm, Microsoft_VC80_MFC_x86.msm, Microsoft_VC90_CRT_x86.msm, Microsoft_VC90_MFC_x86.msm, etc, they can cause the problem. To verify, build your MSI package without these merge modules and see if the uninstaller runs faster. If it does not, I'm sorry, I can't help you, but if your uninstaller runs significantly faster, you should be able to correct the problem. Another troubleshooting step could be running uninstaller for the MSI containing the merge modules with logging enabled and checking the log entries. The command line for this should be similar to:
msiexec /uninstall "PATH TO YOUR MSI FILE" /l*vx "PATH TO OUTPUT/LOG FILE"
In my log file, when the installer appeared hanging, I saw a repetition of the same pattern of log messages that looked like these:
Action start 13:07:24: SxsUninstallCA.
1: sxsdelca tried opening key w/o wow64key  2: Software\Microsoft\Windows\CurrentVersion\SideBySide\PatchedComponents 3: 380 4: 0
MSI (s) (E8!C8) [13:07:24:507]: Closing MSIHANDLE (235) of type 790531 for thread 200
MSI (s) (E8!C8) [13:07:24:507]: Creating MSIHANDLE (236) of type 790531 for thread 200
1: sxsdelca tried opening wow64key  2: Software\Microsoft\Windows\CurrentVersion\SideBySide\PatchedComponents 3: 404 4: 0
MSI (s) (E8!C8) [13:07:24:507]: Closing MSIHANDLE (236) of type 790531 for thread 200
MSI (s) (E8!C8) [13:07:24:507]: Creating MSIHANDLE (237) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 1158 4: 0
MSI (s) (E8!C8) [13:07:24:507]: Closing MSIHANDLE (237) of type 790531 for thread 200
MSI (s) (E8!C8) [13:07:24:507]: Creating MSIHANDLE (238) of type 790531 for thread 200
MSI (s) (E8!C8) [13:07:24:507]: Creating MSIHANDLE (239) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 1186 4: 0
MSI (s) (E8!C8) [13:07:24:507]: Closing MSIHANDLE (239) of type 790531 for thread 200
MSI (s) (E8!C8) [13:07:24:507]: Creating MSIHANDLE (240) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 732 4: 0
MSI (s) (E8!C8) [13:07:24:507]: Closing MSIHANDLE (240) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 748 4: 0
MSI (s) (E8!C8) [13:07:24:507]: Creating MSIHANDLE (241) of type 790531 for thread 200
1: scavenge 2: {121634B0-2F4B-11D3-ADA3-00C04F52DD52} 3: {98CB24AD-52FB-DB5F-C01F-C8B3B9A1E18E} 4: {AEA1383C-9A90-406A-8CAE-718170D9CBDA} 5: -1
MSI (s) (E8!C8) [13:07:24:507]: Closing MSIHANDLE (241) of type 790531 for thread 200
...
...
...
MSI (s) (E8!C8) [13:16:37:663]: Creating MSIHANDLE (180783) of type 790531 for thread 200
1: scavenge 2: {EDDF99D9-9FE3-4871-A7DB-D1522C51EE9A} 3: {42CDEC6E-1259-F078-C01F-C8B3B9A1E18E} 4: {AEA1383C-9A90-406A-8CAE-718170D9CBDA} 5: -1
MSI (s) (E8!C8) [13:16:37:663]: Closing MSIHANDLE (180783) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 748 4: 0
MSI (s) (E8!C8) [13:16:37:663]: Creating MSIHANDLE (180784) of type 790531 for thread 200
1: scavenge 2: {0EFDF2F9-836D-4EB7-A32D-038BD3F1FB2A} 3: {42CDEC6E-1259-F078-C01F-C8B3B9A1E18E} 4: {AEA1383C-9A90-406A-8CAE-718170D9CBDA} 5: -1
MSI (s) (E8!C8) [13:16:37:663]: Closing MSIHANDLE (180784) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 748 4: 0
MSI (s) (E8!C8) [13:16:37:663]: Creating MSIHANDLE (180785) of type 790531 for thread 200
1: scavenge 2: {4D7B7CF9-E7EA-4404-B148-0C8B8A520E35} 3: {42CDEC6E-1259-F078-C01F-C8B3B9A1E18E} 4: {AEA1383C-9A90-406A-8CAE-718170D9CBDA} 5: -1
MSI (s) (E8!C8) [13:16:37:663]: Closing MSIHANDLE (180785) of type 790531 for thread 200
1: sxsdelca 2: traceop 3: 748 4: 0
Reason
I'm not quite certain why this is happening, but apparently the problem only occurs under certain conditions, i.e. the same MSI package that includes Visual C or MFC runtime merge modules may work fine on some systems and hang on others. For more information, check the See also section.

Solution
This may not be the most elegant solution, but in the absence of alternatives, to fix the problem, do not process Visual C and MFC runtime components during uninstallation. In the MSI terms, you need to delete the SxsUninstallCA action from the CustomAction table in the MSI package.

ActionTypeSourceTarget
SxsUninstallCA1SxsUninstallCACustomAction_SxsMsmCleanup

You can delete this record manually using Orca, but it would be more convenient to automate the operation, which you can do with the help of the WiRunSql.vbs script. The script comes with the Windows Installer Software Development Kit (SDK). Once you install the SDK, you can find the WiRunSql.vbs file in the location similar to:

C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\sysmgmt\msi\scripts\WiRunSQL.vbs

You can copy this file to your project or solution folder and then execute it as a post-build step. For example, if you keep the script in the solution folder, your post-build command in a WiX project may look like this (make sure the command appears on one line):

cscript //nologo "$(SolutionDir)WiRunSql.vbs" "$(TargetPath)" "DELETE FROM CustomAction WHERE CustomAction.Action='SxsUninstallCA'"

Enjoy!

See also:
WinForm app Uninstall involving VC++ runtime libs takes a long tim[e]

Monday, October 18, 2010

WiX how-tos and missing links

Summary: Links to articles explaining how to accomplish different tasks in WiX and other helpful information.
This is post #4 of the six-part Learning WiX series. For other topics, see:

Table of contents
  1. Background (why WiX?)
  2. Introduction (answers to common questions)
  3. Getting started (references and tutorials)
  4. How-to's and missing links
  5. Slides and demo projects
  6. Improved demo projects (32- and 64-bit installers)
Here is a list of articles covering topics that I either did not find -- or found implemented better than described -- in most popular WiX tutorials and wikis:

How to: Exclude license agreement dialog from the dialog sequence
How to: Install a Windows service (see also this and that)
How to: Build 32-bit and 64-bit MSI packages (see this thread, and that one, too)
How to: Add a shortcut (without an icon [.ICO] file)
How to: Add a checkbox to conditionally install a desktop shortcut (via a check box)
How to: Add a desktop shortcut (without a registry key)
How to: Create shortcuts for ALL USERS
How to: Execute custom action (CA) on uninstall only
How to: Create an uninstall shortcut
How to: Launch program after installation
How to: Add a neat checkbox to the exit dialog for launching a program or help file
How to: Create a localized installer and bootstrapper (see also parts 2, 3, and 4)
How to: Modify XML files (e.g. web.config) during installation
How to: Modify web.config file during installation (turn off debug flag, etc)
How to: Implement custom actions (CAs) (excellent explanation of different CA types)
How to: Implement a custom action in managed code (C#/VB.NET)
How to: Implement a major upgrade (see Brian Gillespie's comment for optimization ideas)
How to: Preserve original Windows service configuration on major upgrade
How to: Deploy a web site (also this one)
How to: Save path to installation folder in the registry (search for ARPINSTALLLOCATION; see also this, this, and that)
How to: Override (wrong) Program Files (x86) on x64 machines in WixUI_Advanced sequence
How to: Upgrade application in the original installation folder ()
How to: Make setup UI sequence show only two (Welcome and Final) dialog boxes
How to: Retain user-customized files during a Windows Installer major upgrade
How to: Register a COM+ application
How to: Create an event log source
How to: Deploy publisher policy files to GAC

I also found the following information very insightful (some related to MSI, other about WiX):

Description of TARGETDIR and SourceDir
Explanation of the MergeRedirectFolder variable
Differences between 32-bit, 64-bit, and mixed MSI packages (includes folder locations, package compatibility and other info)
How Windows Installer Processes Packages on 64-bit Windows
List of system folders defined by the Windows Installer engine
Add/Remove Programs (ARP) support (good explanation and illustration of ARP properties)
Windows Installer: Property Reference
MSI Writing Guidelines

I will keep updating these lists updated when I find more useful articles.

See also:
WiX - Windows Installer XML (more how-tos)
WiX tricks and tips (includes a few how-tos)
WiX Tricks (several good suggestions)
WiX Tips & Tricks

Tuesday, October 12, 2010

Learning WiX from ground up

Summary: Reference guide for beginners.
This is post #3 of the six-part Learning WiX series. For other topics, see:

Table of contents
  1. Background (why WiX?)
  2. Introduction (answers to common questions)
  3. Getting started (references and tutorials)
  4. How-to's and missing links
  5. Slides and demo projects
  6. Improved demo projects (32- and 64-bit installers)
So you decided to create your first setup package using Window Installer XML (WiX). Where do you start? And how much do you need to know about WiX and Windows Installer (MSI) to build a working deployment package?

The answer to the second question is: it depends. Well... sort of. Before you begin, you definitely need to know the fundamentals of the Windows Installer (MSI) technology, such as:
  • The overall structure of an MSI package (MSI database)
  • The difference between packages, features, components, and deployment items (files, registry keys, shortcuts, etc)
  • Custom actions (CAs) and how they are used
  • Upgrade types (minor vs. major upgrade)
  • Merge modules
You don't need the in-depth knowledge, but at the very least, you need to understand the terminology (check the Wikipedia overview and MSI Basics). You may need to learn more to implement such complex features as program shortcuts (yes, shortcuts are complex in Windows Installer), but you will be able to learn additional concepts as you go.

To get started, install the current version of WiX Toolset from:
You can download a beta version of the upcoming release or an older version of WiX Toolset from SourceForge.

I assume that you will be using Visual Studio to develop setup programs. WiX Toolset includes a Visual Studio add-on, Votive, that enables WiX integration with the Visual Studio IDE. After installing WiX Toolset, make sure that WiX project templates appear in the New Project dialog box:

At this point, you can create a WiX project, but when you open the auto-generated WiX source file, you'll realize that you have no idea what to do with it. This is where a tutorial can help.

The WiX Toolset's help file is a good place to start (by default, the help file is installed to C:\Program Files\Windows Installer XML v3\doc\wix.chm; you can find a shortcut to the help document under the WiX program group in the Start menu; the help file can be also viewed online). You don't need to read it all; the first few chapters and how-to articles give you a basic idea of what you need to do to get a functional setup project.

To get more in-depth understanding of WiX, check out more advanced tutorials. The ones I found most helpful include:
There is also a very insightful presentation by Jeffrey Sharp (with slides and video):
The following MSDN article by Ibrahim Hashimi is a bit out-of-date and has a slightly different focus (build automation), but it still offers a pretty decent overview of WiX:
Nick Ramirez just published an excellent book that covers a lot of WiX and Windows Installer (MSI) topics (see my Amazon review):

You can read the Getting Started and Adding a User Interface chapters online.

And here is a list of tools that you may want to check out:
  • SharpSetup creates bootstrapper and GUI for your WiX installer in C# and WinForms.
  • Wix# (WiXSharp) builds MSI packages or WiX source code from C# code.
  • IsWix (Industrial Strength Windows Installer XML) is a document editor that enables non-setup developers to collaborate with setup developers using WiX projects.
  • WixEdit is an editor for XML source files for the Windows Installer XML (WiX) toolset to build MSI and MSM setup packages.
After you feel more comfortable with WiX basics (deploying files, etc), your next challenge will be implementing slightly less obvious operations (registering COM objects, creating shortcuts, using custom actions, etc) that are either not covered in the help file and popular tutorials or covered incompletely. In the next post, I will include the list of references to the how-to articles that I found most helpful.

Friday, October 8, 2010

Introduction to WiX

Summary: Answers to most likely questions from Windows Installer XML (WiX) novices.
This is post #2 of the six-part Learning WiX series. For other topics, see:

Table of contents
  1. Background (why WiX?)
  2. Introduction (answers to common questions)
  3. Getting started (references and tutorials)
  4. How-to's and missing links
  5. Slides and demo projects
  6. Improved demo projects (32- and 64-bit installers)
Here is a list of questions I had a couple of weeks ago before I started working with WiX (Windows Installer XML). I hope that answers to these questions will help other WiX novices.

What is WiX?
WiX is a language (Windows Installer XML [eXtensible Markup Language]), or more specifically, a Windows Installer-specific XML syntax. You can use WiX syntax to author XML source files for your setup project, from which you can then build Windows Installer (MSI) packages with the help of WiX Toolset.

What is WiX Toolset?
WiX is distributed as a free (open-source) toolkit that includes several command-line tools (such as WiX compiler, linker, etc), documentation, and utilities. Once you create WiX source files defining your setup application (you can do it by hand in a text editor, such as Notepad), you can use WiX Toolset to compile these files into a Windows Installer (MSI) package.

Can I develop WiX projects in Visual Studio?
Yes, WiX Toolset's Visual Studio package, Votive, which is also free (and open-source), adds WiX-specific project templates to Visual Studio, so you can create and build WiX projects directly from Visual Studio. Votive also provides syntax highlighting and IntelliSense for WiX source files.

Which version of Votive do I need?
There are several versions of Votive (and WiX Toolset), each targeting specific versions of Visual Studio. At the time of writing, the latest version (v3.5 for Visual Studio 2010) was still in beta. The recommended version (v3.0) works with both Visual Studio 2008 and 2005. Earlier version(s) of the toolset target the earlier version(s) of Visual Studio.

How does Votive/WiX differ from Visual Studio Installer?
Visual Studio Installer (or Setup and Deployment Project Template) allowed you to build setup packages via drag-and-drop activities and automation. It automatically detected dependencies for your application files, generated GUIDs for components and features, and did a few other things in the background, so you may have not even realized that they were happening. When working with WiX projects you must perform all these tasks by hand.

So WiX is not as good as Visual Studio Installer, right?
Yes, and no. It's true that WiX requires more manual work. And it has a steep learning curve. But it's more flexible than Visual Studio Installer, it supports more features and customization, and gives you more control over the resulting setup package. And it produces a much cleaner MSI database.

Does WiX support all features of Windows Installer?
No, unfortunately not. WiX supports many common features of Windows Installer technology, but not all. The list of supported features includes (but is not limited to):
  • 32-bit, 64-bit, and mixed (32/64-bit) installers
  • Creation of shortcuts and registry entries
  • COM server registration
  • Windows service registration
  • Customization of setup dialog sequence (up to certain extent)
  • Creation of web sites
  • And much more
If you wonder about WiX support of a particular feature, check the web for articles and posts on the topic of your interest and you're most likely to find whether WiX support it or not.

Can I use WiX to create a bootstrapper program (setup.exe)?
No, WiX Toolset only allows you to build MSI and MSM (merge module) files.

What are other limitations of WiX?
See the answers posted on StackOverflow.

What are the differences between WiX project types?
In addition to regular installer projects, Votive allows you to build merge modules and WiX libraries. Merge modules let you share installable components among different products. For example, if you want to deploy a common COM component/ActiveX control with different applications, you can encapsulates its installer in a merge module and than use this merge module with regular WiX installer projects (the merge module will be absorbed in each product's MSI package). WiX libraries allow you to share identical sections of XML code between the WiX source files (this is similar to using include files in C/C++ projects).

What do I need to know before learning WiX?
In theory, you should understand Windows Installer (MSI) before you start learning WiX, but in practice you can learn both technologies concurrently. The abundant information available online can help you get started and achieve progress even if you have very limited understanding of Windows Installer.

Where do I find support if I get stuck?
You can start at StackOverflow (I found answer to most of my questions there). The "official" support site is at SourceForge.

I want to try WiX. Where do I start?
This will be the topic of my next post.

See also:
What about that WiX?
Dude, where is your installer?

What about that WiX?

Summary: Reflections from my first encounter with Windows Installer XML (WiX).
This is post #1 of the six-part Learning WiX series. For other topics, see:

Table of contents
  1. Background (why WiX?)
  2. Introduction (answers to common questions)
  3. Getting started (references and tutorials)
  4. How-to's and missing links
  5. Slides and demo projects
  6. Improved demo projects (32- and 64-bit installers)
There comes a time in every Windows programmer's life to face WiX (Windows Installer XML). For me this time came with the news of Microsoft's plan to retire Visual Studio Installer in favor of InstallShield Limited Edition. So I spent the last couple of weeks getting to know WiX and using it to implement installers for several production applications. This is what I learned.

Good news: (1) WiX Toolset let me create installers that were on par with installers I used to build in the good ol' pre-Windows Installer days. (2) I did not have a panic attack when I opened the WiX-generated MSI files in Orca (WiX seem to produce less garbage than say Visual Studio Installer). (3) It took relatively few lines of XML code to build an installer that handled deployment of a Windows service, COM object registration, desktop and shortcut menu creation, invocation of a configuration utility, and typical user interface (setup wizard).

Unfortunately, I cannot say that my transition to WiX was seamless. WiX Toolset has a few limitations. To be fair, some of these limitations are caused by idiosyncrasies imposed by Windows Installer (MSI), but some are native to WiX (e.g. it seems impossible to use the recommended type of custom action when invoking an executable from a merge module). WiX tools sometimes lack features (e.g. it's relatively easy to extract COM registration information from a COM DLL, but there is absolutely no way to do it from a COM executable). There are bugs (probably not as obnoxious as InstallShield bugs, but still). Project documentation and information is skimpy and somewhat confusing (why is the project split between SourceForge and CodePlex? how long should it take a WiX novice to figure out what and how to download the toolkit? why is it called Votive? and why is "i" in "WiX" lower case?) And the WiX learning curve is rather steep, especially for those who have not been intimate with Windows Installer (MSI).

One good -- and bad -- thing about WiX is that it's an open-source project. On the positive side, WiX has a momentum now both inside and outside of Microsoft. On the other hand, it's not clear if, or how long, Microsoft's backing of the project will continue (say, Microsoft strikes another back room deal [I'm speculating here] with Flexera [the InstallShield maker] and withdraws all support from WiX).

As long as you are looking for alternatives, here is a list of commercial products that can help you build MSI-based installers:
Some of these are more popular than others (popularity is often an indicator of the size of the marketing budget than product quality), but I haven't use them to extent of recommending one over the other. [I used to be a huge fan of InstallShield in the late 90's, but after the InstallShield 7 migration fiasco (3 months wasted on a failed attempt to convert a complex InstallShield 6.x project to InstallShield 7, mostly due to bugs in the product) I would not want to re-live the pain.] So for the time being I will stick with WiX.

If you are interested in WiX, read my subsequent posts. I will share (time permits) the things that helped me get started. Here is the outline of the upcoming WiX-related posts (I'll convert items to hyperlinks when the posts are ready):
  1. Introduction to WiX (FAQs for novices)
  2. Learning WiX from ground up (resources for WiX beginners)
  3. WiX how-tos and missing links (helpful how-tos and insights)
  4. Bonus: Presentation and demo projects
  5. Extra bonus: Build 32- and 64-bit installers using WiX (new and improved samples)
See also:
Choosing a Windows Installer Deployment Tool
Dude, where is your installer?
Rob Mensching Does Installations with the WiX Toolset (podcast, transcript)

Monday, February 23, 2009

Implementing Windows services in Visual Studio 2008

Summary: How to write a better Windows service in Visual Studio 2008.

Last week I discovered a couple of problems related to porting my Windows service demo project from Visual Studio 2003 to Visual Studio 2008. A minor problem was caused by an obsolete method in the sample Windows service. Another problem was quite embarrassing: once started, it was impossible to stop a service from Service Control Manager. To fix this problem (and a couple of other issues related to .NET 2.0-specific functionality), I made the following changes:
  • Swapped the contents of Start and OnStart methods (now the Start method calls the OnStart method).
  • Moved the contents of the Stop method to the OnStop method.
  • Removed the Stop method (it's really not needed).
  • Modified the IsInstalled method.
  • Renamed the TestService source file in the demo project to CustomService (to reflect the name of the class).
If you have been using the My.Utilities library to implement a Windows service and are planning to upgrade it to the Visual Studio 2008 version, please use the updated projects (see the download link below) and keep an eye on the following:
  1. Move your custom startup logic of a WindowService-derived class from the Start method to the OnStart method.
  2. Don't forget to call the base class' OnStart and OnStop methods in the corresponding overriden methods.
  3. Well... that's it.
One other thing that I could've done would be using the nullable DateTime members and variables when checking for uninitialized date and time values (instead of DateTime.MinValue), but since this would not improve functionality, I left the current implementation as is. If you strive for code elegance, feel free to do it yourself, since you have the source.

Here is the Visual Studio 2008 version of the project, which incorporates all reported bug fixes up-to-date:Let me know if you encounter any problems.

See also:
Write a Better Windows Service by Alek Davis

Friday, July 18, 2008

Database installer revised

Summary: Overview of changes made to the previously published database installer script (dbsetup.vbs).

I'm not sure what happened to the new and "improved" MSDN Magazine (the web site), but all of a sudden, I started getting messages from readers asking to send them the VBScript file (dbsetup.vbs) accompanying my Data Deployment: Streamline Your Database Setup Process with a Custom Installer article (from the September 2004 issue of the magazine). I checked the site and did not find a download link, so I'm offering* the most recent version of the script here:


I'd also like to mention a couple of alternatives which you may like better than my approach, but first, let me describe modifications I made to the script in case you insist on using it. (If you don't know how the script works, please read the article; it explains the script execution logic.)

The most recent update to dbsetup.vbs was triggered by an idiosyncrasy in Visual Studio 2008. For some reason, Visual Studio 2008 saves new SQL source files added to database projects in the UTF-8 format, even if the files only contain regular 7-bit ASCII characters. [I could not find an explanation to this phenomenon, but since new files added to other (non-database) projects get saved in the ASCII format, I suspect that the issue is caused by the default file templates associated with the Visual Studio 8 database projects (someone at Microsoft must have accidentally saved these files encoded in UTF-8). I may be wrong, though.]

UTF-8 encoded files containing English (ASCII) text are almost identical to regular ASCII files, except that the former include three special bytes called byte-order mark (BOM) identifying the encoding format in the beginning of the file. Most programs, such as text editors, can handle UTF-8 encoding (you may not even notice that the file is UTF-8 encoded), but unfortunately, VBScript (the scripting engine) is not one of them.

When opening a text file in VBScript, you can specify whether the file is encoded in ASCII (TristateFalse) or Unicode (TristateTrue), but if you specify the Unicode format, VBScript will assume that the file is encoded as UTF-16, which is not the same as UTF-8. Because VBScript did not (and still does not) support the UTF-8 format, the original version of dbsetup.vbs could not process UTF-8 formatted files (the returned database error complained about invalid characters).


To handle UTF-8 encoded files, I added a workaround: when processing text files (SQL scripts and others), dbsetup.vbs now looks for the Unicode byte-order marks. If the script finds the UTF-8 specific bytes, it discards them and processes the rest of the file as regular ASCII text (Note: If you want to include real Unicode characters in text files, use UTF-16 encoding, which VBScript and dbsetup.vbs can handle). This workaround is not very elegant, but it seems to work.

Two other modifications affect repair scripts (scripts executed to repair a database without incrementing its version). To provide support for multiple database versions (in source control), dbsetup.vbs now expects to find repair scripts under the version labels in the Repair folder (the Repair folder is expected to have subfolders named after the database versions to which they apply, similar to the approach used for grouping the upgrade scripts). Also, to make sure that repair scripts added during test cycles get executed during production deployment, dbsetup.vbs will process them after an upgrade (only repair scripts defined for the current version will be processed).

Finally, dbsetup.vbs now supports conditional execution of scripts. If you want to selectively include certain scripts, keep them in a subfolder (under a regular folder) named after a directive you'll use when running setup and/or enclose the file references in the #if DIRECTIVE ... #endif code block (replace DIRECTIVE with a meaningful name) if you explicitly name the scripts in of the Files.txt files. To include the script, launch dbsetup.vbs with the /set command-line parameter followed by a directive you want to include, such as /set:DIRECTIVE. When dbsetup processes a folder, it first handles regular scripts, and then, if launched with the /set command, it will process all conditional files from the subfolders matching the directives included in the /set command, or the conditional sections of the Files.txt file.

I have to say that there may be better database deployment methods than my simple process. For example, you can try using Database Schema Build & Deployment Tools offered by Database Edition and Team Suite of Visual Studio Team System 2008.

Tip: In addition to Microsoft, other third-party vendors started offering database installation tools, such as:

A couple of weeks ago, I read an article Deploying Database Developments** in which Alexander Karmanov describes an alternative database deployment methodology. Although Alexander's approach seems a bit more complicated (then, say, my technique), it may offer a more comprehensive solution. I didn't have much time to delve into Alexander's solution, but you may want to give it a try.

Additional references:
Get Your Database Under Version Control by Jeff Atwood
Evolutionary Database Design by Martin Fowler and Pramod Sadalage
11 Tools for Database Versioning by secretGeek



*I wrote dbsetup.vbs in a rush a few years ago, so now, when I'm looking at the source code, I can see how imperfect it is. Frankly, I'm a bit ashamed that this code has been made public, but I also do not want to waste time rewriting the parts that work. Anyway, if you are eager to criticize the programming style and approach, I'm with you.
**Does the title Deploying Database Developments sound right to you? Development is a process, so how do you deploy a process? You can deploy an application, code, etc, but development... I don't think so.

Thursday, February 21, 2008

Microsoft ate my uninstaller

Summary: Microsoft thinks that program uninstall shortcuts under the Start menu are bad. What say you?

The most common methods of uninstalling software include two options:
  1. the Add or Remove Programs Control Panel (or an equivalent program), or
  2. a shortcut under the Start menu's program group (or Uninstall shortcut).
Although many programs create Uninstall shortcuts, Microsoft discourages this practice. In Designed for Windows XP Application Specification, Microsoft suggests:
"Do not place shortcuts to remove the application in the Start menu. It is not needed because your application’s uninstaller is in the Add or Remove Programs Control Panel item." (Section F1.1)
In addition to the stated reason, Microsoft does not favor Uninstall shortcuts because they (supposedly) add clutter to the Start menu:
"Usability studies show that when the Start menu and/or Windows Desktop become too cluttered, users have a very difficult time finding and launching their programs. This leads to a bad user experience." (Section F1.1)
I don't buy the last argument because when users complain about the Start menu clutter, they probably imply the main Programs group folder. Since Uninstall shortcuts appear under the application sub-folders (and not directly under the main Programs group folder), they do not make the Programs group folder more cluttered than it already is. Besides, with Vista improvements and so many available alternatives, Start menu clutter becomes less of an issue. [After adopting Launchy, I hardly use the Start menu.]

With respect to the "application’s uninstaller [being] in the Add or Remove Programs Control Panel" argument, I have to mention that the Add or Remove Programs Control Panel... kinda... sucks! Let's see what it takes to uninstall a program via the Uninstall shortcut and compare it to the Add or Remove Programs approach.

Option 1: Use the Uninstall shortcut
  1. Click the Start menu; select Programs-Application folder-Uninstall.
  2. Follow the prompts.
This was fast. Now, how do we get to the same step via the Add or Remove Programs control panel:

Option 2: Use Add or Remove Programs
  1. Click the Start menu; select Settings-Control Panel.
  2. Wait a few seconds (minutes) for Control Panel to load.
  3. Control Panel loads. Select (or double-click) the Add or Remove Programs option.
  4. Wait for the list (of installed applications) to be populated. (Go to Starbucks... Get a cup of Frappuccino... Come back...)
  5. OK, the Add or Remove Programs list is finally populated. Now, find the application. (Scroll down looking for the application name... Scroll up looking for the software maker name... It is not uncommon for the entries in the Add or Remove Programs control panel to have names different from the applications under the Start menu. Sometimes the Add or Remove Programs Control Panel contains entries with duplicate names.)
  6. Once you find a reasonable match, select the program and click the Uninstall button.
  7. Follow the prompts.
Although the performance of the Add or Remove Programs Control Panel in Windows Vista has somewhat improved, it's still not the most efficient way of removing software. Maybe this is why a number of applications, including CCleaner, MyUninstaller, Revo Uninstaller, and ZSoft Uninstaller, promise to offer a better uninstallation experience. [After trying a few of these alternatives, I have not been convinced that their application removal features offer any drastic improvements over the Add or Remove Programs Control Panel.]

Not only does it take longer to launch uninstaller from the Add or Remove Programs Control Panel, but what would you do if Control Panel stopped working. This happened to me a few times. For example, a couple of weeks ago I installed a recommended anti-virus tool, and several programs -- including the Add or Remove Programs Control Panel -- started to malfunction (I could not even launch the Add or Remove Programs Control Panel). Attempts to kill or suspend the offending application process did not help, but because the application had the Uninstall shortcut, I could quickly remove it and bring my system back to normal. Without the Uninstall shortcut, fixing the problem would've taken much longer.

If you want to implement the Uninstall shortcut for your application, but not sure how, check Google (look for the solution applicable to your installer technology). For MSI-based installations, use a shortcut with the following command line (replace Product_Code_GUID with the actual value of ProductCode):

msiexec /x{Product_Code_GUID}
To implement an Uninstall shortcut in a Visual Studio 2005 deployment project, do the following:
  1. Add Windows system folder

    Select the setup project in Solution Explorer, click the File System Editor icon. Right-click anywhere (except the currently displayed folders) in the File System Editor view, and select the Add Special Folder - System Folder to project menu option.

  2. Add msiexec.exe file to project

    In File System Editor, right-click System Folder, and select the Add - File... menu option.


    In the Add Files dialog box, select the msiexec.exe file located in the Windows system folder (such as System32) and click the Open button.

  3. Create the Uninstall shortcut

    Double-click the application folder under the User's Programs Menu and right-click anywhere on the empty space of the right panel of the File System Editor (make sure that none of the items are selected); select the Create New Shortcut menu option.


    In the Select Item in Project dialog box, double-click System Folder, and select msiexec.exe; click OK.

  4. Set the Uninstall shortcut properties

    Select the Uninstall shortcut and press the F4 key to display the shortcut properties window. Rename the Uninstall shortcut to something more meaningful, like Uninstall (it may make sense to include the name of your application). Set the value of the Arguments property to /x[ProductCode] (you can enter the GUID of the product code, but then you would need to remember to update the shortcut property if you change the GUID).

Note: When you build the setup package, you will get the following warning (the path to the msiexec.exe file may be different):
WARNING: 'msiexec.exe' should be excluded because its source file 'C:\WINDOWS\system32\msiexec.exe' is under Windows System File Protection.
You can ignore this warning.

Additional references:
Application Specification for Microsoft Windows 2000 Server
Application Specification for Microsoft Windows Server 2003
Dude, where is your installer?

Friday, February 1, 2008

Dude, where is your installer?

Summary: Don't make your application users suffer: offer them an installer.

Last year, Jeff Atwood wrote an article, in which he mentioned a hassle of installing applications, which do not have installers. After describing the manual steps it takes to prepare such application for its first run, Jeff concluded:
"That's a lot of tedious, error-prone steps I have to perform before I can run the application. [...] Is this really what we want to subject our users to?"
Judging by the growing number of applications, which come without installers, the answer to Jeff's question is: "Absolutely!" And not only do we (programmers) want to subject our users to these tedious, error-prone steps, we somehow managed to make them believe that this is a good thing. Read what CyberNet's Ryan wrote about an application called Pitaschio:
"[Pitaschio] caught my attention not only because it was freeware, but also because it didn’t require any installation. Those two ingredients are pretty important when it comes to making a good first impression on me."
Now, Ryan, wait a minute... It didn't require any installation? Are you sure?

With the exception of portable programs (such as Portable Apps intended to run from USB drives), any application requires some form of installation. Installation can be manual (extracting files from a ZIP file, copying them to folders, creating shortcuts) or it can be done with the help of a setup program. Whenever someone claims that an application does not require any installation, he (she) probably means that the application does not have an installer and must be set up manually. Why this is considered a good thing is beyond me because it normally takes more effort to install a program manually.

Let's compare the steps it takes to install a hypothetical program consisting of a single executable file with and without an installer.

Option 1: Installation steps (with installer)
  1. Download the ZIP file.
  2. Extract installer file(s) from the ZIP file (to a temporary folder) and launch the setup program (good installers do this in one step).
  3. Once the setup program starts, click the Next button to select the default options (for the application folder, and so on) until setup completes (most installations can be done in three clicks or less without lots of thinking).
  4. (Optional) Delete setup file(s) from the temporary folder (again, good installers do this automatically).
  5. Delete the ZIP file.
The key point here is that the user is not forced to think and can just go: click, click, click (the mouse), or hit, hit, hit (the Enter button). Here are the steps, which I often perform to install a program manually.

Option 2: Installation steps (without installer)
  1. Download the ZIP file.
  2. Extract the application file from the ZIP file to... Hmm, where should it go? (Thinking...) I guess, I'll save it under the Program Files folder.
  3. Open Windows Explorer (click, click to start Windows Explorer). Locate the Program Files folder (click, click, click, more clicks to navigate to the Program Files folder).
  4. Okay, I'm in the Program Files folder, but how do I name a folder for the new app? (Thinking...) I guess, I'll name it after the application executable. Select File-New-Folder from the menu, enter the name of the new folder, hit Enter.
  5. Extract the application executable to the newly created folder.
  6. Switch back to the application folder in Windows Explorer and create a shortcut (right-click the executable, select Create Shortcut from the menu, click F2 to rename the shortcut, enter a more user-friendly name, hit Enter).
  7. Create a new program folder under the Start menu (click, click, click, more clicks to navigate to the Programs folder under the Start menu, select File-New-Folder, enter the name of the new folder, hit Enter).
  8. Copy the application shortcut to its program folder under the start menu.
  9. (Optional) To auto-start the program, copy its shortcut to the Startup folder; otherwise, copy the shortcut to the Quick Launch menu (again a few more clicks).
  10. Delete the ZIP file.
Would someone (Ryan?) be so kind to explain what makes option 2 better than option 1, because it's not obvious.

One argument in favor of installer-free applications claims that these applications are easy to uninstall: just delete the application file(s) and it's gone. I can't agree with this argument because it attributes "clean" application behavior (the fact that the application does not use Windows registry or any other persistent storage) to lack of installer. Besides, most client programs rely on persistent storage for tasks such as storing application data and user preferences, which (according to the most recent guidelines) should not be kept in the program folder, but saved in the user's application data directory (such as AppData). This means that when uninstalling the program, I need to find and manually delete data files, as well as the program file(s) and shortcuts located in various folders (Program Files, AppData, desktop, Start menu, Startup folder, Quick Launch menu). Again, how is this easier than launching the uninstaller and letting it handle all cleanup tasks for me?

There is one valid argument in favor of installer-free programs: support for portable execution. If an application is intended to run from a portable device, such as a USB drive, it should not require an installer. However, this does not mean that the application should not provide an installer for regular (non-portable) use.

Smarter developers, such as the makers of my favorite text editor PSPad, offer users both installation options: with and without installers. I hope that one day I will see installers for other great programs, including:If you are a developer, who haven't written an installer before, you may not realize that (for simple applications) it requires very little effort. You can build a simple installer using Visual Studio's Setup and Deployment Project templates. Or use one of the following FREE tools:Lists of other installer authoring tools can be found here:If you are totally new to the world of installers, the following references will help you get started:

Build an Installer for Installer-less Programs
Deploying a Windows-based Application
How to create a Setup package by using Visual Studio .NET
Step-by-Step Process of Creating a Setup and Deployment Project
More articles...

See also:
From MSI to WiX
It's the installation, stupid
Software and Support for Setup Developers
Windows Installer resources
Installers (list of free and commercial installers)