/build/static/layout/Breadcrumb_cap_w.png

A General Approach to Software Packaging - Propagating user settings

The goal of this blog post is to provide an overview of the most common means of getting user settings in place for each user that starts an application. While it is in no way my intention to reiterate materials that are already available, I want to give an overview of choices.

I will stick to what might be called the Windows-Inherent options, so I will not go deeper into things like AppSense or Citrix User Profile Management.

 

USER SETTINGS – WHAT ARE WE TALKING ABOUT?

While I could spend a lot of time expanding on this topic, I like to remember that basically every windows application (and package) is made up of 2 things: files and/or registry keys. That’s it, nothing more, nothing less.

So when talking User Settings what we basically mean are

  • FILES in the locations on a machine that make up the user’s personal workspace, his profile to be exact. Specifically for packaging we’re talking about a user’s UserProfile and the ApplicationData that is contained within.
  • REGISTRY KEYS that go into the user-specific  registry hive, HKEY_CURRENT_USER or HKCU

 

SO WHAT’S THE PROBLEM WHEN GETTING THESE SETTINGS IN PLACE?

Usually when installing an application through MSI in a corporate environment, these installation are done ‘per-machine’ as opposed to the other option ‘per-user’

What this means is that all the application data is written in a way to allow every user on the target machine to use the application. MSI-technically this is linked to the ALLUSERS property, the value of which will determine the location where this data ends up.

However at time of installation (often done in LOCALSYSTEM context) it is not always possible to put all user-specific data in place, simply because not all users can be known at time of installation. While one could conceivably run through the file and registry locations for each user known on the machine at time of installation, and put the files and registry keys in place, what about new users that log in?

So a mechanism is needed to put this data in place for each specific user, either when they log on, or at the latest when they start up the application. In this post I will distinguish between 4 options:

  1. MSI advertisement: the most ‘core’ of the options in that it makes best use of the Windows Installer options available, this will propagate settings when the user starts the application
  2. Active Setup: A Windows mechanism (not Windows Installer) that allows execution of commands when a user logs on
  3. MSI repair: often used in combination with Active Setup as a trigger, I will treat this separately from option one since there are some key differences.
  4. RUN and RUNONCE registry keys: while these are generally considered to be inferior options, I will mention them for the sake of completeness

The table below gives an overview of these mechanisms with some key properties

Name

Technology

Execution Timing

Repetition

Advertisement

Windows Installer

At application launch

At every launch

Active Setup

Windows Native

At user login

Once for each user

MSI repair

Windows Installer

When desired, usually user login

Depends on trigger

RUN/RUNONCE

Windows Native

At machine startup or user login

Once or every time

Let’s now run through the options, in descending order of desirability

 

MSI ADVERTISEMENTS

This will always be your best option, and hence your first choice. The idea is to use the tables in your MSI to create what is called an Advertised Entry Point into your package.  The best known method for creating such an entry point is the Shortcuts table, but this is NOT THE ONLY OPTION!!

Generally, when an advertised entry point into an MSI is triggered, this triggers the Windows Installer Self-Healing mechanism. This mechanism works as follows:

  1. Windows Installer detects the feature that the entry point is part of
  2. For all components in this feature, Windows installer checks for the presence of the component key-paths
  3. If a key-path, whether it be a file or registry key, is missing, a repair of  the all the components in this feature is triggered (feature level repair)
  4. If no missing keypaths are detected in the initial feature, a check will be done on the parent feature, and if any missing keypaths are found, Windows Installer will initialise a check on ALL features in the MSI. Any repairs done at this point though are done per component, not for the entire feature (component level repair)

 The fact that a check on missing keypaths is made, and a repair is only triggered if said keypath is not in place implies that you should give each component that contains user settings a keypath that is a HKCU registry key. Since this will never be in place before the self-healing has completed the installation for that user, you can be sure that the self-healing will be triggered. A simple value like HKCU\SOFTWARE\<Your Application>\UserSettings = 1 will suffice here.

 Now let’s run through the MSI tables that may contain such advertisement data. Before doing so however a small sidestep into COM Objects is necessary

 

COM or Component Object Model is a language-neutral way of implementing objects that can be used in environments different from the one in which they were created, even across machine boundaries. So to put it simply, it allows programmers to write code that can be re-used on a system by other programs (using DLLs or EXEs or OCXs).

This means that these components need to implement well-known interfaces to provide a standard way of approaching them, and they need to be uniquely registered by the operating system. This is where the CLSID comes into play.

A CLSID is a 128 bit key or GUID that uniquely identifies one of these COM objects. In the Windows registry such CLSIDs can be found at

 [HKEY_CLASSES_ROOT\CLSID\{<clsid>}]

 This key contains the info that links this class to a dll, exe or ocx file that contains the specific code implementation.

 Since these GUIDs can be troublesome to work with, it is allowed to link a CLSID to a simpler ProgID (PROGrammatic IDentifier), which is a more readable, non-unique name linked to a CLSID that has the form <Program>.<Component>.<Version>. These ProgIDs are stored in the registry under

 [HKEY_CLASSES_ROOT\{<ProgID>}]

 When a dll is shared by multiple CLSIDs some settings for this dll, like security, can be handled centrally across these CLSIDs. For this purpose one can identify an AppID. This is also a 128bit GUID. An individual class can be linked to such an AppID by adding a named value, "AppID" under their CLSID key in the registry.

[HKEY_CLASSES_ROOT\AppID\{<AppID>}]

[HKEY_CLASSES_ROOT\CLSID\{<clsid>}]

"AppID" = "{<appid>}"

 

Now let’s finally run through the MSI tables that allow for advertisement

Shortcuts table

As stated, the best known option. You create an advertised shortcut in your package that points to any file inside the msi, and each time a user clicks the shortcut, it will trigger the self-healing check, with the entry-point being the component that contains the advertised shortcut.

 Class table

This table is used to register a COM object to the Operating System, as discussed above. When this registration is advertised, Windows Installer will add a so-called darwin descriptor to the data in the registry. This darwin descriptor, which looks like a string of gibberish, is actually a hashed pointer to a product-feature-component combination which makes up the entry point for Windows Installer Self-healing. As soon as any application (most notably the one in your package) tries to use this COM object, a self-heal will be triggered.

 ProgID table

As discussed above ProgIDs allow for higher level naming of (sets of) CLSIDs. The ProgID table contains an optional foreign key (Class_) that links it to the Class table and hence a certain CLSID. The triggering mechanism for self-healing is essentially identical to the one for the Class table.

 Extension table

In this table you link file extensions to their associated executables. When advertised, clicking a file with the registered extension will call Windows Installer Self-healing.

 Verb table

The Verb table is used for associating context-menu entries when clicking files with a certain extension, and identifying the command that should be run when clicking this menu entry. Again using this functionality will trigger Self-healing.

 Typelib table

This table is used for registering Type Libraries, however, since there is a strong advisory from Microsoft against using this table, I will not go into detail on it here. The advisory states that the needed entries should be entered directly in the registry instead of using this table.

 MIME table

The MIME table associates a MIME content type with a file name extension or a CLSID to generate the extension or COM server information required for advertisement of the MIME (Multipurpose Internet Mail Extensions) content.

 

ACTIVE SETUP

I sometimes like to consider Active Setup as a ‘poor man’s alternative to advertisement’, in the sense that, if possible, I would always prefer the use of advertisement in an MSI over Active Setup. There are however plenty of circumstances where you just cannot use advertisements in the MSI, so then Active Setup really becomes the next choice.

The principle behind Active Setup is simple. It sets up a way to run a command once for each user that logs into the machine. Core of the system is the list of registry keys found under

[HKLM\Software\Microsoft\Active Setup\Installed Components]

Every subkey here is the reference of one Active Setup. Once the Active Setup command has run for a certain user, an equivalent key is written to that user’s HKCU registry hive. Three important values can be distinguished under each of these keys:

  • @(Default): the friendly name for the action. This is the text which will appear in Microsoft’s “Applying Personal Settings for…” window that shows up when a user logs on
  • StubPath: this is the command that will execute once for each user that logs into the machine. It can be any command, considering that it gets executed in User Context, so the user should have sufficient privileges to execute this.
  • Version: versioning allows for rerunning the StubPath command. When the version is increased in the HKLM key, the Active Setup will run again for each user. This can bypass the problem of having to delete Active Setup keys for all users when we want to rerun the command.

Often the StubPath command used is actually an msiexec command that will trigger a repair of the installer MSI (msiexec /f …). We will go into this in the next section.

 

MSI REPAIR

By running msiexec.exe with a /f parameter and pointing it to an MSI file or a ProductCode, we can trigger a repair of this MSI. A full list of msiexec parameters can be found at http://support.microsoft.com/kb/227091, but the most commonly used combinations for User Setting repair are:

Msiexec /fu {ProductCode} : repairs all user-specific registry settings

Msiexec /fup {ProductCode}: repairs all user-specific registry settings and reinstalls missing files

 

The reason why I want to mention this mechanism separately from MSI self-healing, is that self-healing and repair are not the same thing. Where self-healing is a process that gets triggered from data within the MSI itself (advertised entry points), and get initiated from a specific component and feature, MSI repair is triggered by an external command, and does not initiate as fine-grained a process. There is no feature cascade done during the reinstall of missing files and registry keys.

Since the repair gets triggered by a msiexec.exe command line, more often than not, the aforementioned Active Setup is used to trigger the process.

 

RUN/RUNONCE registry keys

To me (note that this is subjective, but hey) this is really not as viable an option as the previous ones. I mention it for the sake of completeness, but will only give it a cursory treatment.

The RUN and RUNONCE keys can be found in the registry under

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce

Values under these keys may contain commandlines that will be run either every time (RUN) or once (RUNONCE), either starting the next time the machine starts up (HKEY_LOCAL_MACHINE) or the next time the specific user logs on (HKEY_CURRENT_USER)

Personally I tend to think the combination of available options with Self-Healing, Repair and Active Setup should be enough to cover any scenario of User Settings propagation, so I almost never use this last option. The RunOnce key is too limited in my view for User Settings, and the Run key, since it triggers every time, runs unnecessarily often in my view.

 

This concludes this post giving an overview of User Setting propagation techniques. The key point that I wanted to get across is that there is, in my opinion, a cascading list of techniques to do this. Cascading in the sense that some should be preferred over others because they are more tightly linked to Windows Installer. I know there is more to be said on the subject, but that will be for future blog posts. That does not mean that I do not appreciate feedback, or am unwilling to change/extend/adapt this post based on that feedback :-)

 

Kr,

PJ

 


Comments

  • The blog came alive at start of MSI advertising....really well written for guys starting out. Two thumbs UP!!! - akki 12 years ago
  • too bad the tables aren't rendering correctly, but I hear they're working on that :) - pjgeutjens 12 years ago
  • It's really good, especially the RUN/RUNONCE info. - bala.munagla 11 years ago
  • I just want to say :
    the "Advertisement" apply at software launch but not at every launch.
    Yes, you can put a registry to "HKCU \ SOFTWARE \ <Your Application> \ User Settings = 1" but this solution force the advertisement one time.
    A other way will be to add a condition installation on the component (Installed, Not REMOVE="ALL" or PROPERTY="Value"... something else) to control if the advertisement have to apply. - egiberne 9 years ago
  • "at application launch" + "at every launch" means everytime you launch the application. Which is correct (try triggering self-healing once and then deleting the keypath). The check will run everytime the entry point gets triggered. Of course actual self-healing only if the keypath is missing..

    I don't follow your remark about conditioning components - pjgeutjens 9 years ago
  • Informative blog. - apptopack 8 years ago
This post is locked

Don't be a Stranger!

Sign up today to participate, stay informed, earn points and establish a reputation for yourself!

Sign up! or login

Share

 
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ