determine install dir from external UI

Feb 19, 2015 at 9:01 PM
Using external ui as shown in your example, how can I find out the INSTALLDIR so a user can have a chance to change it before running the install. Once they change it, how can I apply that to the MSI.

Thanks a lot.

your example only show some button with install("CUSTOM_UI").
Coordinator
Feb 20, 2015 at 9:37 AM
You can use and .NET routine at you disposal to collect user input. It can be console input, winform/WPF text box, FolderSelection common dialog. And when you have user selection you can pass it to the msi as a property value. In this case it is INSTALLDIR.

The ExternalUI concept is in fact extremely simple and the same for all setups of this type (e.g. Visual Studio Blend, SQL Server). You have a full freedom of building any UI you want (not bound by the one MSI/WiX provide for you). You tun this UI and collect user input required foe customization of your MSI. After that you start the MSI with the all customization properties values passed to the MSI as command line attributes.

The examples are showing you
  • how to build MSI that accepts custom installdir: <WixSharp Samples>\InstallDir
  • how to pass custom property to MSI: <WixSharp Samples>External_UI\WinFormsSetup
The only missing piece here is the collecting user input. But this is a trivial .NET (not MSI) task that you will have no problem to find the example for.

Good luck :)
Feb 20, 2015 at 2:45 PM
It is trivial to get user input for the installed directory. I have no problem with that. I have gone through the examples many times and since I'm not familiar with wix, I must miss something very simple.

in the setup.cs:
    _Project project =
        new Project("MyProduct",

            new LaunchCondition("CUSTOM_UI=\"true\" OR REMOVE=\"ALL\"", "Please run setup.exe instead."),

            new Dir(@"%ProgramFiles%\My Test\MyProduct",
                new File(binaries, @"Files\Bin\MyApp.exe"),
new Property("IDIR", "empty")
                new Dir(@"Docs\Manual",
                    new File(docs, @"Files\Docs\Manual.txt"))));

    project.UI = WUI.WixUI_Common;
    project.GUID = new Guid("6f330b37-5578-43ad-9095-1861ba25889b");

    Compiler.BuildMsi(project);
I know I have to put the property there, but how does that relate to INSTALLDIR, do I have to call custom action?

and then in the myproductsetup.cs

I can very easily add the following text with newDirectory = "C:\test\test"


public void StartInstall(string newDirectory)
    {
        StartInstall("CUSTOM_UI=true 1DIR=" + newDirectory);
    }
will somehow change the installdir to C:\test\test


I must miss something...

in the InstallDIr example, the install_customDirectory.cmd has

PROGRAMFILESFOLDER.CUSTOMACTIONTEST="C:\Program Files\CustomDir"

again, how does that relate to INSTALLDIR.

Thanks for your help....

Your Wix# is very powerful if I know how to go about doing this.
_
Coordinator
Feb 21, 2015 at 3:21 AM
The most beneficial technique for any investigation including discovering the relationships between properties and elements is to compile the C# script with the Compiler.PreserveTempFiles = true;. This will preserve temporary wxs file, which is compiled into the actual MSI.

I actually should have pointed you to the InstallDir_AbsolutePath sample, which is simpler and illustrates better the destination directory assignment.

I modified a bit the sample for your scenario (rely on External UI), which is slightly different to the one implemented in the InstallDir sample (rely on MSI UI):
var project =
    new Project("MyProduct",
        new Dir("UNDEFINED",
            new File("readme.txt")));

project.UI = WUI.WixUI_InstallDir;
project.GUID = new Guid("6f330b47-2577-43ad-9095-1861ba25889b");

Compiler.PreserveTempFiles = true;
Compiler.BuildMsi(project);

If you run the code above it will build MSI from the emitted wxs as below:
<?xml version="1.0" encoding="Windows-1252"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="6f330b47-2577-43ad-9095-1861ca25889c" Name="MyProduct" Language="1033" Codepage="Windows-1252" Version="1.0.0.0" Manufacturer="OSH" UpgradeCode="6f330b47-2577-43ad-9095-1861ba25889b">
    <Package InstallerVersion="200" Compressed="yes" SummaryCodepage="Windows-1252" Manufacturer="OSH" Languages="1033" />
    <Media Id="1" Cabinet="MyProduct.cab" EmbedCab="yes" />

    <Directory Id="TARGETDIR" Name="SourceDir" >
      <Directory Id="INSTALLDIR" Name="UNDEFINED">

        <Component Id="Component.readme.txt" Guid="6f330b47-2577-43ad-9095-18615e463af3">
          <File Id="File.readme.txt" Source="readme.txt" />
        </Component>

      </Directory>
    </Directory>

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"  />

    <Feature Id="Complete" Title="Complete" Absent="allow" Level="1" >
      <ComponentRef Id="Component.readme.txt" />
    </Feature>

    <UIRef Id="WixUI_InstallDir"  />

  </Product>
</Wix>
You can now see that INSTALLDIR is always assigned by Wix# to the destination directory (unless you specify different ID) . This ID can also be used as a property in the MSI command line arguments (or StartInstall(...)).
msiexec /i myproduct.msi INSTALLDIR="C:\test\CustomDir" /q
Feb 21, 2015 at 8:34 AM
Thanks for your help,

so in my startInstall, I should do

StartInstall("CUSTOM_UI=true INSTALLDIR=\"C:\test\CustomDir\" /q ");

and whether I do

project.UI = WUI.WixUI_InstallDir;

or
project.UI = WUI.WixUI_Common;
won't make any difference.

I did try modify the external UI sample to reflect that, but I must miss something, it seems to always refer to the old msi.
Feb 21, 2015 at 9:01 AM
seems to work now, pretty nice.

StartInstall("CUSTOM_UI=true INSTALLDIR=C:\test1\CustomDir");

if I tried to put /q, it complains and said it is an invalid command argument. Other than that, it works.

Thanks
Coordinator
Feb 22, 2015 at 1:39 AM
Great.
Yes the /q is a pure MsiEecx command line argument and it should not be used with StartInstall

project.UI = WUI.WixUI_InstallDir;

Does not make a difference because it is an instruction for the MSI runtime how to initialize MSI UI but in your case you are not using MSI UI as you are building your own.
Mar 2, 2015 at 2:36 PM
using External_UI/WinFormsSetup as the starting point, this is basically what I have done. Hopefully, it will save a new user some times implementing this solution.

In myproductSetup.cs, add this

public void StartInstallWithAgrument(string agrument)
    {
        //string agrument = string.Format("CUSTOM_UI=true INSTALLDIR=\"{0}\"", FullPath);
        StartInstall(argument);
    }

In MsiSetupForms.cs, modify installBtn_Click to call
void installBtn_Click(object sender, EventArgs e)
    {
        DisableButtons();
    string agrument = "CUSTOM_UI=true INSTALLDIR=\"c:\\whatever\"";
    session.StartInstallWithAgrument(agrument);
     }
The argument is hard coded for now, you can use FolderBrowserDialog to allow a user to select which folder to install.

Hope that helps