0
votes

I am playing with WiX for a few weeks now, and I want to install a file to the D:-drive if it isn't a CD-ROM drive. Otherwise it has to be installed to C:.

I created this Custom Action to see if a drive is fixed and ready:

    [CustomAction]
    public static ActionResult CheckDataDrive(Session session)
    {
        ActionResult retVal;

        session.Log("Begin CheckDataDrive");
        if (TrySetTargetDir("D", session))
        {
            retVal = ActionResult.Success;
        }
        else if (TrySetTargetDir("C", session))
        {
            retVal = ActionResult.Success;
        }
        else
        {
            retVal = ActionResult.Failure;
        }
        session.Log("End CheckDataDrive");

        return retVal;
    }

    private static bool TrySetTargetDir(string driveLetter, Session session)
    {
        var driveInfo = new DriveInfo(driveLetter);
        if (driveInfo.DriveType != DriveType.Fixed || !driveInfo.IsReady)
            return false;

        // Set the INSTALLFOLDER
        session["INSTALLFOLDER"] = session["INSTALLFOLDER"].Replace(session["TARGETDIR"], $"{driveLetter}:\\");
        session.Log($"INSTALLFOLDER changed to {session["INSTALLFOLDER"]}");
        return true;
    }

And this is what I have in the Wix product:

    <Feature Id="ProductFeature" Title="SetupGatewayFiles" Level="1">
        <ComponentGroupRef Id="ConfigFiles" />
    </Feature>

  <InstallExecuteSequence>
  <!-- Sets TARGETDIR to either D:\ or C:\ -->
    <Custom Action='CheckDrive' After="CostFinalize" />
  </InstallExecuteSequence>

And the rest is in this fragment:

<Fragment>
  <Binary Id="CustomActionBinary" SourceFile="$(var.CustomAction1.TargetDir)$(var.CustomAction1.TargetName).CA.dll" />
  <CustomAction Id="CheckDrive" BinaryKey="CustomActionBinary" DllEntry="CheckDataDrive" Return="check" />

  <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="INSTALLFOLDER" Name="Configurations" />
    </Directory>

  <ComponentGroup Id="ConfigFiles" Directory="INSTALLFOLDER">
    <Component Guid="{C5AF7E80-4D59-47CD-A537-2BC4BE90FDE3}" Id="ProductComponent" >
      <File Source ="Application.xml" />
    </Component>
  </ComponentGroup>
</Fragment>

The Custom Action seems to work, because this is what I see in the log file:

MSI (s) (14!B4) [18:49:46:510]: PROPERTY CHANGE: Modifying INSTALLFOLDER property. Its current value is 'D:\Configurations'. Its new value: 'c:\Configurations'.

Property(S): INSTALLFOLDER = c:\Configurations\

But the file is still installed in D:\Configurations! What am I doing wrong?

2

2 Answers

0
votes

After="CostFinalize" seems too late to schedule such an action. Can you try replacing that with:

    <Custom Action='CheckDrive' Before='CostInitialize'>
0
votes

After trying Robert's answer, I discovered TARGETDIR is not initialised before CostFinalize (and thus before CostInitialize), so I get an exception TARGETDIR being empty. And after CostFinalize it is too late. So I tried a different approach: I didn't want to reuse parts of the properties TARGETDIR and INSTALLFOLDER, so I completely hard-coded the path in de CustomAction. And I followed Robert's solution to be earlier to set the value. So this is what I ended up with:

    private static bool TrySetTargetDir(string driveLetter, Session session)
    {
        var driveInfo = new DriveInfo(driveLetter);
        if (driveInfo.DriveType != DriveType.Fixed || !driveInfo.IsReady)
            return false;

        // Set the INSTALLFOLDER
        session["INSTALLFOLDER"] = $@"{driveLetter}:\Configurations";
        session.Log($"INSTALLFOLDER changed to {session["INSTALLFOLDER"]}");
        return true;
    }

And do the Custom Action earlier in the sequence:

<Custom Action='CheckDrive' Before='CostInitialize'>

And setting the INSTALLFOLDER with a non-usable value:

<Directory Id="INSTALLFOLDER" Name="tbdInCustomAction" />