Formatting Properties

Formatting Properties

  • Comments 5

A frequently asked question is about why property values in the Property table aren't formatted when the values contain properties themselves, such as:

[ProductName] is copyright by [Manufacturer].

The reason these property values aren't formatted is because the Value column type is simply Text, not Formatted. Other formattable column types exist, including Template and Condition types. Since properties can be included in formattable strings, the Property table does not allow formattable values because it could create a circular reference, such as with the following example archive file format:

Property    Value
s72 l0
Property    Property
A   [B]
B   [A]

Your own custom actions or external UI handler can format these properties, however, using the MsiFormatRecord function. To avoid circular references, format only private properties and make sure those properties are not authored to contain circular references such as those in the example above. Windows Installer provides some protection as documented in the Property table, but take care to not workaround this protection,

Note that you cannot use the Property table to set a property to the value of another property. The installer does nothing to the text string entered in the Value column before setting the property in the Property column. If FirstProperty is entered into the Property column and [SecondProperty] in the Value column, the value of FirstProperty is set to the text string "[SecondProperty]" and not to the value of the SecondProperty property. This is necessary to prevent creating circular references in the Property table. Instead, you can set one property to another by using a Custom Action Type 51.

Leave a Comment
  • Please add 6 and 3 and type the answer here:
  • Post
  • Suppose you have these rows in the Property table...

    Property Value
    s72 l0
    Property Property
    a [b]
    b [c]
    c d

    What will be the result of calling MsiFormatRecord on a record whose
    field 0 contains "[a]"?  Will it be "[b]", "d", or something else?

    It seems unlikely that I'll be able to test this myself, but I'm
    assuming the result will be "[b]".  If it were "d", then Formatted
    columns (such as Registry.Value) could not safely refer to properties
    that hold the names of folders (such as DesktopFolder), because there
    is no guarantee that the names of those folders don't contain paired
    brackets.

    But if the result is "[b]", then circular references can never cause
    MsiFormatRecord to fall into an infinite loop, so I don't see what
    your advice to "format only private properties" was all about.
  • Kalle, the result would be "[b]". In your example of the Registry.Value column, it would be best to include the [DesktopFolder] property if that is your intention. In cases were problems like this do occur, however, you can use a type 51 custom action. Many installers will do this to set the default TARGETDIR.

    I mentioned to format only private properties to help avoid the issues because a custom action could work around the protections put in place by Windows Installer by formatting a buffer repeatedly to get the desired effect, knowing the limitations mentoined in the Windows Installer SDK. By formatting only private buffers, the install package developer should be reasonably confident such a circular reference wouldn't exist.

    As for trying these things out, I'd recommending using WIX from http://wix.sourceforge.net. It's simple to whip up a .wxs file, compile and link it, and test it. A dozen lines of XML or so will make you a nice, full-blown product installation. I actually have several WIX projects I keep lying around that test different scenarios so that with minor tweaks I can save time prototyping design ideas to help make our patches better. This is just some advice you might consider.
  • Yes, I am aware of WiX.  But I don't have Windows at home, and if
    I try MsiFormatRecord scenarios at work, I probably won't post
    about that here.

    I am curious about your mention of CA type 51, though.  Firstly,
    what do you mean with "problems like this"?  I thought you just
    confirmed that there is no problem with using e.g.
    "[DesktopFolder]" in a Formatted string.

    Secondly, how does one set a default TARGETDIR with it?  If it's
    a default, then it should be overrideable, but if one just puts
    the custom action in a sequence table, then it will take
    precedence over any TARGETDIR property specified on the command
    line.  So there should be a condition in the sequence table, but
    how can one test whether the TARGETDIR property was specified by
    the user or defaulted by Windows Installer?  (I hypothesized on
    one such test in <news:873bqocooe.fsf@Astalo.kon.iki.fi> last
    July, but perhaps it doesn't work.)
  • There is no problem using [DesktopFolder] in a formatted string, but I was referring to problems where users might use one property to dereference another. Typically in a Registry.Value column you might just have something like "[#file]", "[PersonalFolder]My App", or something similar.

    You can set the TARGETDIR to a default value like "[ProgramFiles][Manufacturer]\[ProductName]". Visual Studio's Windows  Installer projects do this by default. Additionally, if you don't want to override command-line property settings put a condition on the action in the sequence tables "NOT TARGETDIR" so that the type 51 CA runs only if the property is not already defined. Your hypothesis is correct, though. I've tested this scenario as well as similar ones to make sure user overrides aren't overridden.
  • Ah, it looks like I had misunderstood the time when Windows Installer
    implicitly sets TARGETDIR.  I had believed that, if TARGETDIR is
    defined neither in the command line nor in the Property table,
    then Windows Installer would generate a default value based on the
    ROOTDRIVE property before it runs any sequence tables.  But now as
    I reread the documentation, it looks like that only occurs during
    CostFinalize.  That sure makes things simpler.
Page 1 of 1 (5 items)