[wix-users] Strategies for Reducing Installer Code Duplication

Todd Hoatson todd.hoatson at gmail.com
Fri Sep 18 13:05:09 PDT 2020


As a follow-up for my previous email (attached below), I have some
questions about the use of Fragment elements...

In "WiX 3.6: A Developer's Guide to Windows Installer XML", by Nick
Ramirez, I read the following:

"The Fragment element doesn't need any attributes. It's simply a container.
You can place just about anything inside of it, such as all of your
Directory elements or all of your Component elements."

"... properties, which are variables that you can use to store data, are
represented by Property elements and could be stored in a separate file
within a Fragment element. Then, by referencing just one of them in your
main source file with a PropertyRef element, you'd pull all of them into
your project. With fragments, it's all or nothing. Referencing one element
in the fragment references them all."

"Launch conditions check for prerequisites at the beginning of the
installation and prevent it from continuing if their requirements aren't
met. They're placed anywhere inside either the Product element in your
main.wxs file, or a Fragment element in a separate file."

"Fragments can be used to split your code into separate files and as such
can be used for many different purposes. To create a dialog out of one..."

"The PackageGroup element, which I've included in a separate Fragment
element..."

So, little-by-little I develop a picture that Fragment elements can contain
"just about anything", specifically including the following elements:

- Directory
- Component
- Property
- [Launch] Condition
- UI
- PackageGroup (not Package?)

Looking at the Wix Toolset Documentation for the Fragment element, I see
many other elements listed.

What's not so clear is what elements cannot be contained in a Fragment.  It
seems Product is excluded, along with InstallUISequence,
InstallExecuteSequence... are there others?

Also, in the Fragment element description I read:

"When linking in a Fragment, it will be necessary to link in all of its
individual units. For instance, if a given Fragment contains two Component
elements, you must link both under features using ComponentRef for each
linked Component. Otherwise, you will get a linker warning and have a
floating Component that does not appear under any Feature."

Is this really an issue related to fragments, or is it simply an issue of
components and features?  Is this simply saying that a component, once
defined, must be assigned to a feature, and cannot be left hanging around
ambiguously?  If that's true, then the placement of a component in a
fragment doesn't change anything.

Or is this saying that the components defined together in a fragment are
actually brought together into the WiX structure?  This is more a question
of scope.  For example, consider the following WiX code:

    <Feature Id="Always" Title="Required"
             Description="These files are required in order for the Demo
program to run."
             Level="1"   Absent="disallow" >
        <ComponentGroupRef Id="DEMOPROG" />
        <ComponentRef Id="DesktopShortcut" />
        <ComponentRef Id="AppMenuShortcuts" />
    </Feature>

If there are component groups defined in a given fragment, in addition to
DEMOPROG, will they be implicitly brought into the "Required" feature?  Or
are they simply made available for reference in some part of the WiX code?

Directory elements are more confusing...  I see that components can be
defined inside them:

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="MyProgramDir" Name="Install Practice">
          <Component Id="CMP_InstallMeTXT"
Guid="E8A58B7B-F031-4548-9BDD-7A6796C8460D">
            <File Id="FILE_MyProgramDir_InstallMeTXT"
Source="InstallMe.txt" KeyPath="yes" />
          </Component>
        </Directory>
      </Directory>
    </Directory>

Or they can be done inside DirectoryRef elements:

    <DirectoryRef Id="MyProgramDir">
      <Component ...>
        <File ... />
      </Component>
    </DirectoryRef>

Conversely, the Directory and Component can be specified together on a
ComponentGroup element:

    <ComponentGroup Id="ProductComponents" Directory="MyProgramDir">
      <Component ...>
        <File ... />
      </Component>
    </ComponentGroup>

So Directories and DirectoryRefs can contain Components, but not
ComponentRefs or ComponentGroups or ComponentGroupRefs...?
And a Directory can be specified by Id on a ComponentGroup, but not on a
Component or a ComponentRef...?

So it would seem impossible to define the components in a Fragment and then
define a directory structure in the main WiX file with references to those
components.  Correct?

At the same time, it seems inadvisable to have a mutual dependency between
the main WiX file and the fragment file by defining the directory structure
in the main file and referencing it within the fragment file, while at the
same time defining the ComponentGroups within the fragment file and
referencing them within the main file.  Or is that no big deal...?

And I believe that ComponentGroups are typically defined along with the
components.  But consider the following:

    <ComponentGroup Id="ProductComponents" Directory="MyProgramDir">
        <ComponentRef Id=" Comp1" />
    </ComponentGroup>

    <Fragment Id="CompFrag">
        <Component Id="Comp1" .../>
        <Component Id="Comp2" .../>
        <Component Id="Comp3" .../>
    </Fragment>

Given that the components are defined in their own fragment, would a
reference to one component in the ComponentGroup bring all the others into
the same group?  What if I wanted them to end up in different groups?
Would the components each need to be in their own fragment, as heat does?

These ambiguities and complexities are making it difficult for me to decide
on a strategy for eliminating as much duplication as possible in our WiX
code.

Todd
On Thu, Sep 17, 2020 at 5:56 PM Todd Hoatson <todd.hoatson at gmail.com> wrote:

> Our application has a somewhat complex installation strategy...
>
> A "Base" installer with a full UI that can take 2 forms (or Bundles):
> - full package including prerequisites for users without reliable internet
> access
> - partial package for users with reliable internet access to download
> prerequisites
>
> A Patch installer without a UI that is used for automatic updates from
> within our product
>
> Each bundle is described by a .wxs file, but there is a good bit of
> duplication between the two, for example:
>
> It seems like both bundles could use the same .wxs file, but simply have
> the prerequisites in separate fragments (e.g. NetFx48 downloader or NetFx48
> installer) in separate files and include the correct file for each bundle.
>
> Is that a reasonable strategy for bundles?
>
> The situation for the base vs. patch installers is more complicated...
>
> The patch bundle has a lot of the same attributes for the bundle element,
> but the rest of it is stripped down.  There doesn't seem to be a good
> strategy for reducing this duplication.
>
> Also, the patch process builds two .msi files - one representing the
> shipped product, the other representing the updated product.  For this we
> have 2 .wxs files which are identical, except for a comment at the top.
> This can be easily remedied.
>
> But, again, there is a duplication between the .wxs for the base .msi and
> the .wxs for the patch .msi.  The Product, Package and Upgrade elements are
> basically the same.  The Directory hierarchy is largely the same, but
> different stuff is interspersed.  The main difference is in the UI - so
> they have different InstallExecuteSequence contents, and the patch .wxs has
> no InstallUISequence.
>
> What would be a reasonable strategy for reducing the duplication here?
>
> --
> Todd Hoatson
> Mobile: 763-291-3312
> Email:   todd.hoatson at gmail.com
> www.linkedin.com/in/toddhoatson
>


-- 
Todd Hoatson
Mobile: 763-291-3312
Email:   todd.hoatson at gmail.com
www.linkedin.com/in/toddhoatson



More information about the wix-users mailing list