Logo

Update of pp

5/5/19

As part of the Visual Studio 2017 upgrade, pp was recompiled. At this time WixApp has been created and it is being used to create the Product.wxs file used by Wix to build an installer. It also uses SetEnv to install a link to the pp.exe in the system Path variable. Both SetEnv and WixApp are discussed else where.

My Library is used with pp but it is not included here. Look for it elsewhere in the site.

Introduction

I am using Visual Studio 2013 version. I am also using SlickEdit for most of the editting and compiling tasks. So where did I begin this journey. I originally installed (copied) pp to C:\Local\ and manually placed a link in System.Path to "Local". That was probably 4 PCs ago (late 90s). Recently I've embarked on cleaning up several development projects. One of the tasks was to provide an installer for a couple of the projects. Then as these things go I just had to add an installer to all of the projects.

The Print Program (pp) is a command line program out of the dark ages. As described in the Modules page, it has some redeaming capabilities so I've kept it alive all these many years. This last week (October 2017) I wanted to create an installer for it. Visual Studio 2013 doesn't support an installer but by "adding" one to Visual Studio from the Microsoft Toolkit (add link) a Microsoft "approved" (if that is the right adjective) installer is available. The documentation for the installer is very clear: No support for adding a program's path to System.Path. Furthermore there is no way to invoke an external program to do the job for the installer.

Searching for a solution yielded one interesting suggestion: Wix. Wix would allow invoking an external program but everyone agrees that it is a difficult program to understand and use.

Wix

Wix is not a procedural language. It more or less is a description of some things that should happen when the Microsoft installer is invoked with the data in the ".msi" file. Wix provides a way to supply the data needed.

My purpose in this little paper is not to document Wix but rather to document those things I learned the hard way. Wix is adequately documented online and in at least one book: " Wix 3.6: A Developer's Guide to Windows Installer XML " by Nick Ramirez published by PACKT. Start on page 1 and construct the example "Amazing ..." in Chapter one and work through the next few chapters adding and modifying the example. This will prove to one that Wix works.

Wix Reality

Now I want to document those things in Wix that caused me trouble so that the next time I embark on a Wix adventure I have some help to avoid the issues I discovered this time around. Here is a pdf file of the Product.wxs that produces the installer for pp.

Getting Started

The Wix File must begin with two XML lines.:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
But following those lines at least four different XML statement types can appear:
<?define ...?>
<?include ...?>
<Product ...>
<Fragment ...>
One of the issues is that the "include" statement may only appear after the initial two lines and outside of any of the other XML structures. Note that XML requires that the Product tag is closed by a corresponding </Product> and the Fragment tag must be closed by a corresponding </Fragment>. It would have been nice if an include statement could appear between the Product tags.

One of the issues was providing one declaration for the directory in which the files could be found. There is an extensive mechanism for identifying the location where the files should be installed (by files I mean the executable, shortcuts and data files). However all the documentation I've read (which is admittedly not all that much) always use just the file name as if the file is in the same place as the Wix file. The define tag allows one to define a variable which can define the path. In this installer I also need the path to three files which I may use in several places.

<?define SourceDir = "$(var.SolutionDir)\Release\" ?>
<?define WixInclude = "D:\Sources\WixIncludes\"?>

The WixIncludes content may be found here. It is included with the Print Program because it is required there to create an installer.

Product

The Product block is the outer entity of the install package. It includes the following tags:

  • Package
  • MajorUpgrade
  • MediaTemplate
  • User Interface (UI) Declaration and Modification
  • Icon Declarations
  • External Executable Declarations
  • Feature Block
The first three are documented adequately in the aforementioned book. The Feature Block lists only one ComponentGroup reference leaving the actual list of features to install to the Component Group.

There are four predefined user interfaces. The one chosen, WixUI_InstallDir, allows just one change, the destination directory. However it also requires the user accept a license agreement, you know the one that nobody reads. I searched high and low for a way to skip the license agreement. The UI block changes the control flow from the Welcome Dialog to the InstallDir Dialog.

Windows is an Icon rich interface. The user interface has a standard bit map for both the side of dialog box and a banner about the white area used for text. They have special names and can be replaced. The program may be represented by icons in various places. There are typically two such icons, one for the program and one for the uninstall program. In this instance they are the same as the only program that needs an icon is the uninstall program. The ARPPRODUCTICON is another special name the places the icon mentioned in tag in the Control Panel/Programs and Features (Win 7).

The last interesting section of the Product Block is the Custom Action declaration. In my search for an installer that would add a path to System.Path Wix provided a way to do that. A custom program could receive information directly from the installer during both an install and an uninstall. The programs job would be to add and delete the path from System.Path.

The order of the Custom Action tags is important. I tried two different organizations for the Custom Action declarations. The first was to place the Custom Action declarations in a Fragment. Didn't cause a compile error but the custom action did not run. Oh well. The second organization was to place the Custom Action declarations in an Wix include file (i.e. .wxi) and place the <?include ... ?> just before the Feature block. No joy there either.

Fragments

The two fragments are just used to separate pieces of the Product. They are discussed at length in the Wix 3.6 book. The Properties ApplicationFolderName, WIXUI_INSTALLDIR and WixAppFolder are used in the UI.

SetEnv Path

Update 5/5/19

SetEnv is called from the Wix Installer when necessary (and instructed by the user in WixApp).

2017 Comments

Searching the internet and the Visual Studio 2013 Help files I found the functions:

  • Environment::GetEnvironmentVariable
  • Environment::SetEnvironmentVariable
They are only available in CLR programs and I chose a console program. The libraries used are incompatible with most of the "normal" C/C++ libraries. After much teeth gnashing over the System::String functions I worked through logic to add to the System.Path and remove from System.Path. When adding to System.Path the program must verify that the path does not already exist in System.Path. When removing the program must find where the path resides in System.Path. In both cases there are five cases for the location of a specific path in System.Path. System.Path contains zero or more paths, each path separated for another by a semicolon (';'). The five cases are assuming that the given path is not null:
  • System.Path is empty
  • System.Path has one path, i.e. the given path. In this case no semicolon follows the path
  • System.Path has two or more paths and the first one is the given path, i.e. the given path is followed by a semicolon
  • System.Path has three or more paths and the given path appears between semicolons
  • System.Path has two or more paths and the last path is the given path, i.e. it is not followed by a semicolon

The SetEnvPath source is here. (5/5/19) SetEnv is now compiled separately.

Another gotcha occurred recently with the SetEnvPath program. There was a problem with the latest version of WinZip (v22). I was a good citizen and ran a number of experiments for the WinZip folks to see if we could isolate the problem. One of those experiments required me to remove all but the most recent versions of the Net Framework from my system. Unfortunately, SetEnvPath's compilation requires Net Framework 4.6.1 (I believe it is the last version that may be used in Visual Studio 2013 (VS13)).

So I spent a good deal of time trying to get VS13 to accept a later version but that was not to be. I finally reloaded a clean version of the Net Framework 4.6.1 target package and that fixed the problem.

Shortcuts

There are at least two places that a shortcut to the executable should appear. One of those places is in the Start Menu in a Folder with a name on it that indicates the product (either a company name or the name of the program). The other place might be the desktop.

Wix provides at least two ways to specify the shortcut. One way is to include the shortcut inside a Fragment and DirectoryRef separated from the actual program declaration. The program reference may be given with a '#' followed by the id of the program. Unfortunately there is another feature of the start menu shortcut, 'Advertise="yes"', that causes a warning when the shortcut is in a Fragment. The Advertise attribute of the shortcut will place program shortcut between the pinned shortcuts and the "All Programs" button. So take a look at the AwesomeProduct.wxs.pdf file to see a solution to the warning, i.e. placing the shortcuts in the same Component as the file to which the shortcut points. In this case instead of being inside of a Directory Reference the shortcut must include a Directory attribute to specify where the shortcut is to go