Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
201 views
in Technique[技术] by (71.8m points)

windows installer - How do I avoid common design flaws in my WiX / MSI deployment solution?

How do I avoid common design flaws in my WiX / MSI deployment solution?


Deployment is a crucial part of most development - failed deployment means your end user will never get to evaluate your product. This could easily be the most expensive error to make in software development. Please give this content a chance. It is my firm belief that software quality can be dramatically improved by small changes in application design to make deployment more logical and more reliable - that is what this "answer" is all about - software development.


This is a Q/A-style question with an answer that just list a few things not to do in your MSI file to avoid the most common design flaws.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

WiX / MSI Deployment Anti-Patterns

There are several deployment anti-patterns often seen in WiX / MSI files. Below is a rough-draft of some of the most common ones.

Before going into the problems, on the other hand here is a quick reminder of the things that have made MSI an overall success! (despite its problems).

This answer is a work in progress

What do you know I hit the max size for the answer. I guess that's a hint it's enough already :-). Some sections need clarification and improvement though.

If you recognize some of these problems, you might want to read on - these are all well known developer hates and annoyances with Windows Installer / MSI:

  • You cannot reliably overwrite a lower version file with your newest setup.
  • You cannot reliably overwrite non-versioned files (for example for IIS).
  • Files are mysteriously missing after you try to install an MSI upgrade.
  • Data gets wiped out during (major) upgrade scenarios. Examples include:
    • Your registry stored license key.
    • Data in configuration files such as config.xml, settings.ini, etc...
    • Your service credentials for the service you don't run as LocalSystem.
  • Data does not get updated:
    • Settings files are not reliably updated during installation with new settings you want to enforce.
    • You have problems updating settings in data files stored per user (or HKCU). You update for the installing user, how do you update for other users?
  • You see self-repair kick in unexpectedly for your package.
  • Your custom action makes the setup bomb out with mysterious errors.
  • And this is a big one: you unnecessarily use custom actions for things that is already fully supported by the Windows Installer itself. This is a huge deployment anti-pattern, and the leading cause of deployment failures.
    • You install Windows Services via custom actions. This is much better done in the MSI itself using built-in constructs.
    • You install .NET assemblies to the GAC via a custom action. This is fully supported by Windows Installer itself without a line of (risky) code.
    • You run custom .NET assembly installer classes. These are to be used for development and testing only. They should never be run as part of deployment. Rather your MSI should use built-in constructs to deploy and register your assembly.
    • You run prerequisite setups and runtime installers via a custom action in your own MSI. This should be done entirely differently. See section 6.
  • You have problems deploying shared runtime files.
  • Silent installation of your MSI appears to result in a different installation state than running the setup interactively.

The sections below are in no particular order at all - as of now.

The sections are continually sought to be improved. Please add comments on what isn't clear or helpful.

Pending addition:

  • Difficult multi-instance installations
    • Relatively common requirement, especially for service installations
  • Uninstall is not working for MSI application - Error 1722
    • Service control: Failing to stop services before uninstalling
    • Uninstall CAs: Trying to run batch files / scripts that are no longer on disk during uninstall
    • Custom Actions: Erroneous conditioning so custom action runs unexpectedly. Often on uninstall or during major upgrades.

1. Self-repair problems

A particularly annoying problem is related to constructs that frequently trigger unwanted self-repair for your installed application.

  • Due to the multi-faceted nature of this problem, I have created a separate answer to describe the design constructs to avoid in order to prevent self-repair from striking without warning and intent for your application: How do I avoid triggering MSI self-repair with my WiX / MSI package?.

  • Sometimes self-repair is used as a method to populate HKCU with application settings, or put files in each users's user profile. This generally works, but is in my opinion not the best practice for application design and deployment - see more details below in section 9.

2. Incorrect installation of shared, vendor or Microsoft runtime files

Although this is extensively explained in the link above (self-repair issues), it should be noted here as well that one of the most common errors in any setup is the inclusion of "local copies" of shared runtime files - sometimes also globally registered on the system if they are COM files. The installers for old VB6 applications sometimes did this for common controls they required, breaking the system for other applications.

  • If you need a particular version of a shared file for COM use, and there is no way you can update your application to use the properly installed, shared component, then you can use registration-less COM. Essentially installing local copies of the binaries you need and force their loading over shared files via manifest files provided for the binaries.

  • See the self-repair issues link in item 1 above for more details on this topic.

3. Incorrect handling of (your own) shared files and data

If you create a suite of MSI files to deploy different products, they might share certain files between them. If you target the same file location (absolute path) from several MSI files - each using a different component GUID, then each setup will treat the file as if it "owns it" - happily uninstalling it on uninstall, or putting it in place again via self-repair.

  • The proper solution for this is to realize that for every absolute path you target, there must be a single component GUID. Absolute paths are reference counted by a component GUID - and it must be shared between all your setups for this to work correctly.

  • To achieve using the same component GUID in all your setups you should either create a merge-module to include in each setup, or use advanced constructs in WiX such as "include files" - with hard coded GUIDs for the components contained in them.

  • If the file in question is a data file that should never be uninstalled or replaced once updated, you should also consider installing it as a "permanent component" so that it is not uninstalled during major upgrades or manually run uninstalls.

4. Component creation errors - not following best practice

Not following best practice for component creation. MSI components are the basic installation units for files and registry settings.

  • There are best practice rules for how to "componentize" your application files. Breaking these rules can cause problems for patching and upgrades with mysterious symptoms such as missing files and settings after upgrades, or patches that bomb out with nonsensical errors.

  • To counter this problem the oversimplification is that you should use one file per component unless the number of files in your setup is truly enormous. This avoids all kinds of problems (read that link for a more thorough explanation of component ref-counting).

5. Upgrade problems relating to user data being overwritten or reset

This is no less than extremely common. I have answered several stackoverflow questions on this topic, and it keeps coming up.

  • Please read the section called "Overuse of per-user file and registry deployment" for a description of how to minimize the reliance on Windows Installer for user-data deployment in general. If you ask me this is the real answer to these persisting "data reversion" problems.

  • Since upgrades are complex in MSI, many standardize on major upgrades (the simplest form of upgrade). A major upgrade is essentially an uninstall and a reinstall of the same product (in different versions).

  • There are several ways to configure such a major upgrade, but if you uninstall the previous version completely before installing the new version, you could uninstall user data files that have been modified since installed. MSI does not check if data files have been modified since installed and will happily uninstall them without hesitation, unless you have marked the hosting component as "permanent" (it will never be uninstalled) or set a blank component GUID for the hosting component (a special feature to install the file and then ignore it completely).

  • A special case to be aware of is that even if you properly share such a file by using a merge module or WiX include file (to keep the installing component GUID stable)- it will likely still be uninstalled and reinstalled by a major upgrade if there is just one product on the box that has it referenced it at the time (reference count is 1).

  • After the major upgrade has completed it looks as if the data files have been overwritten or reverted, but in actual fact the modified data files were simply uninstalled and then reinstalled in their "fresh versions" (will update with some potential fixes for this soon).

  • In my opinion you should only install data files that are used read-only after installation. If the files should be written to, they should be generated by the application itself in my opinion, and stored in the user-profile. This is an example of how application design can be changed to make deployment more reliable. The "real solution" in my opinion.

  • If you do install the read/write data file with a component, set it permanent (or use blank GUID). The file overwrite rules will ensure that the file on disk isn't overwritten during installation (unless you do something stupid such as setting REINSTALLMODE to amus to force overwrite all files - this should never be allowed. It can downgrade shared files installed by merge modules as well - old-style DLL Hell). If you do want to wipe the file out and overwrite it, that is also possible using various methods, the best of which is probably to use a companion file. (more details will be added later).

  • Wix: Windows S


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...