How to install multiple subdirectories under ProgramFiles64Folder

Dec 2, 2015 at 9:13 AM
I have made a WixSharp 64bit installer that should install files under two different directories under "Program Files". Here is a stripped down version of the code:
using System;
using WixSharp;
using File = WixSharp.File;

public class Script {

    public static void Main(string[] args) {
       var project =
           new Project("My Product",
               new Dir(@"%ProgramFiles%",
                   new Dir(@"SubDir1", new File(@"Files\test2.txt")),
                   new Dir(@"SubDir2", new File(@"Files\test2.txt"))
               ));

        project.Platform = Platform.x64;
        project.GUID = new Guid("6f330b47-2577-43ad-9095-1861ba25889b");    
        Compiler.BuildMsi(project);
    }
}
The problem is that the subdirectories will be created under "c:\%ProgramFiles64%\" instead of being under "c:\Program Files\".

If I just install one sub-directory, then the directory will be installed correctly into "c:\Program Files".

If I do the same without specifying the platform as x64 the files will correctly go under "c:\Program Files(x86)".

What am I doing wrong here? How could I get the two directories there.

I first suspected I might be hitting the wrong overload of the Dir constructor, but the behavior is the same when using the following code to ensure it goes into the Dir(string targetPath, params WixEntity[] items) constructor:
       new Dir(@"%ProgramFiles%",new WixEntity[] {
            new Dir(@"SubDir1", new File(@"Files\test2.txt")),
            new Dir(@"SubDir2", new File(@"Files\test2.txt"))
        }
Coordinator
Dec 3, 2015 at 12:07 AM
The problem you are experiencing is caused by not having a single root installation dir.
Wix# still assigns (as it always does) the INSTALLDIR to the first common parent %ProgramFiles%. However this in turns breaks the MSI Id assignment constrain for the well-known directories (e.g. Program Files). This can be easily avoided by you defining the dir id explicitly:
new Project("MyProduct",
            new Dir(new Id("ProgramFiles64Folder"), "%ProgramFiles%",
                new Dir(@"SubDir1", new File(@"Files\test2.txt")),
                new Dir(@"SubDir2", new File(@"Files\test2.txt"))
                 ... 
This will install the files as you would expect. However, your whole scenario creates an ambiguity about your installation directory. What is it? Is it SubDir1 or SubDir2? You will have difficulties of engaging any functionality that relies on the concept of a single root install directory (MSI fundamental paradigm). MSI InstallDir dialog will pick your first sub dir and treat it as the install dir and will completely prevent you from changing the second one. Wix# ManagedUI dialogs are under the same scrutiny too.

Everything would work just fine if you only have a root directory defined:
new Project("MyProduct",
            new Dir("%ProgramFiles%\MyProduct",
                new Dir(@"SubDir1", new File(@"Files\test2.txt")),
                new Dir(@"SubDir2", new File(@"Files\test2.txt"))
                 ... 
Marked as answer by JanMattsson on 12/2/2015 at 11:49 PM
Dec 3, 2015 at 6:49 AM
Thank you Oleg for the quick answer and the workaround.

The real case from which the example was stripped, is an AutoCAD plugin which I'm developing which must be installed under the "Program Files/AutoDesk/ApplicationPlugins/" so that Autocad will find it and load it. The plugin is communicating with our own product which is installed under another program files subdirectory.

Initially I had made two separate installers, one for the plugin and one for our own product. But our PO wanted a single installer to run to make it easy for the user, which is quite understandable. So I combined the two installers into one, but apparently this is a bad approach as there is no common installdir folder.

What would be a good way of handling the above scenario? Should I use a bootstrapper that runs two separate msi:s?
Coordinator
Dec 3, 2015 at 10:12 AM
OK, I see. Then indeed you need to have multiple install dirs.
.
  1. The problem is that you are assuming that AutoCAD is installed in ProgramFiles. But what if it's not (e.g. user changed the installdir). Then you have a real problem. Your plugin integration will be broken. One of the most reliable approaches is to make the plugin deployment a part of your product configuration step. Thus you can pack the plugin into your product msi and after the installation you start you app config util. In this util at startup you can dynamically locate the AutoDesk (according various algorithms) and deploy the plugin files there. This very same config utill will allow user to remove/update the plugin file anytime without resorting to ARP. This is in fact a common and recommended approach for post Vista Windows. However it is only applicable if the plugin manual deployment involves no more than just copying a few files.
    .
  2. However if you are certain in the AutoDesk location (e.g. it doesn't allow user to change the installdir) then you can go with the solution from my previous post. Just remember that your product dir supposed to be first. In this case MSI will allow user to change your app installdir but not the plugin dir.
    .
  3. An alternative approach indeed would be a bootstrapper.
Arguebly #2 is the simplest one.