Wixsharp: Set INSTALLDIR in bootstrapper ?

Created on 12 May 2020  路  9Comments  路  Source: oleg-shilo/wixsharp

Hi,
I'm trying to get rid of the MSI dialog boxes and implement all user's choices in the bootstrapper's UI (BootStrapperApplication + WPF ). I'm starting with the most basic property: INSTALLDIR but it seems I'm not doing it the right way. The user choice is correctly carried out to the MSI as a variable, but then I don't know how to dynamically change the installation directory.
I tried the following:

private static void OnBeforeInstall(SetupEventArgs e)
{
    e.InstallDir = e.Session.Property("DESTINATION").ToString();
}

But with no success :-(
What am I doing wrong? Is it possible?

All 9 comments

Hi,

I believe that your issue is that you are setting the InstallDir property too late (it's a special property that needs to be set soon). Can you try to change the InstallDir in UIInitialized, UILoaded or Load event? I'm using the same UI model (BA + WPF) but switched from handlers to custom actions so I'm not sure which one suits the best.

I also believe that if you wanted to make things easier you could just rename your DESTINATION property (if you set it directly from BA) to INSTALLDIR and it would work automatically.

Thanks, I've got better result now using the Loaded event.
But I think I don't set correctly the path in the files definition.
Here is one of the file to install:
new Dir(Path.Combine("[INSTALLDIR]", "Resources"), new File(Path.Combine(platformPath, "Resources", "world.xml")))

Do you have any advice on this?

All good, I got it right now, I just had to move subfolders declaration inside the main install dir declaration. I'm not sure I'm clear, but your first advice about using the Load event was perfect.
Thanks a lot for your fast and accurate answer !

As you already did it, how do you completely remove any UI for the MSI?

Glad to help.

What do you mean by completely removing UI? Do you want to run the installer from the command line?

There's a Command property in the BootstrapperApplication class which has a GetCommandLineArgs() method so I'm just using something like:

public class CustomBootstrapperApplication : BootstrapperApplication
{
    Engine.Detect();

    if (Command.GetCommandLineArgs().Length != 0)
    {
        HandleCommandLineArguments(Command.GetCommandLineArgs()); // plan action there
    }
    else
    {
        // show UI
    }
}

Looking at the WiX installer example is also recommended quite often (link to Wix BA). They use the Command.Display property which may be useful for you but I haven't tried it personally. I just check & parse the arguments (needed for deploy automation) and determine what to do.

My code skeleton:

private void HandleCommandLineArguments(string[] args)
{
    switch (args[0].ToUpperInvariant())
    {
        case @"\I":
        case @"\INSTALL":
            var argument = args[1];
            PlanInstall(argument);
            break;

        case @"\X":
        case @"\UNINSTALL":
            PlanUninstall();
            break;

        default:
            var errorMessage = $@"Argument {args[0]} does not correspond to any valid action (\i \install, \x \uninstall)";
            Engine.Log(LogLevel.Error, errorMessage);
            MessageBox.Show(errorMessage);
            throw new ArgumentException(errorMessage);
    }
}

But I imagine that something like this could work too (and it looks way cleaner):

switch (Command.Display)
{
    case Display.Embedded:
    case Display.None:
        HideUI();
        break;

    case Display.Unknown:
    case Display.Passive:
    case Display.Full:
        ShowUI()
        break;

    default:
        throw new InvalidEnumArgumentException();
}

Thanks again for your help.
Currently the minimum UI I could setup for the MSI (not for the Bootstrapper) is using this piece of code:
project.UI = WUI.WixUI_ProgressOnly;
which is acceptable to me.
Actually ideally I'd like to force the msi to install like if I had used the following command line
msiexec /i {guid-code} /qn

Please try setting this MsiPackage.DisplayInternalUI = false .

I'm using ManagedProject instead of Project (inherited) and I'm not setting project.UI but ManagedUI = ManagedUI.Empty. Not sure if it's really needed though.

Bingo, exactly what I needed!
I'll have to report installation progress in my UI but I remember having seen such a use case in the samples.
Thanks for your help.

Glad to help. :blush:

ExecuteProgress and Progress event handlers from BootstrapperApplication will be your friends.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mattias-symphony picture mattias-symphony  路  3Comments

marcobeninca71 picture marcobeninca71  路  4Comments

CADbloke picture CADbloke  路  4Comments

ltemimi picture ltemimi  路  5Comments

Chrissyoung1223 picture Chrissyoung1223  路  5Comments