WiX: Passing Install path to managed custom action
Asked Answered
C

7

16

new Day, new Problem;-) Still got to struggle with managed custom action. I already managed it to call an custom action and passing some test data to it. Now I want to replace the testdata with the real data i need. And here the problems starts: I want to call a batch file which was installed in a subdirectory of my installation. Therefore i need to pass the installation path to the custom action. Afaik this can be done using the customactiondata mechanism. But this does not work. When I log the installation I can see that outside of the customaction INSTALLLOCATION is pointing to the correct path, but as soon as i look in the customaction the customactiondata property is empty...

What am I doing wrong?

Merge Module which calls the custom action:

<Module Id="DflHelpInstaller" Language="1033" Version="1.0.0.0">
    <Package Id="f952de58-1dc6-46b3-872a-7a49e2d9ea0a" Manufacturer="DflHelpInstaller" InstallerVersion="200" />

<Binary Id='RegisterDflHelpDll' SourceFile="$(var.REGISTERHELP.TargetDir)RegisterDflHelp.CA.dll" />

    <CustomAction Id='RegisterDflHelp' BinaryKey='RegisterDflHelpDll'  DllEntry='RegisterDflHelp' Execute='deferred' />

    <CustomAction Id="RegisterDflHelp.SetProperty" Return="check" Property="RegisterDflHelp" Value='[INSTALLLOCATION]' Execute='immediate' />

   
    <InstallExecuteSequence>
      <Custom Action='RegisterDflHelp.SetProperty' After='CostFinalize' />
      <Custom Action='RegisterDflHelp' After='InstallFiles' />
    </InstallExecuteSequence>

    <Directory Id="TARGETDIR" Name="SourceDir">
        </Directory>
    <ComponentGroupRef Id="HelpGroup"/>

    </Module>
</Wix>

Outline of the installer Project which use the MergeModule:

....

<Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="ProgramFilesFolder" SourceName="PFFiles">
<Directory Id="Company" Name='$(var.COMPANY)'>
  <Directory Id="INSTALLLOCATION" SourceName='$var.v[SDK_VERSION]'>
    <Component Id="MyBanner" Guid="C8C28B92-9326-4991-BFB1-BBDFDF3653AB">
      <File Id ="Banner.bmp" Source="Banner.bmp" KeyPath="yes" DiskId="1"/>
    </Component>
    <Merge Id ="DflHelpInstaller" SourceFile="DflHelpInstaller.msm" Language="1033" DiskId="1" />
      </Directory>
</Directory>

....

    <Feature Id="Complete" Title="Setup" Description="Installs the SDK on your local machine." Display="expand" Level="1" ConfigurableDirectory="INSTALLLOCATION">
      <ComponentRef Id="Banner" />
      <ComponentRef Id ="UNINSTALLER"/>
      <ComponentGroupRef Id="ReferenceGroup"/>
      <MergeRef Id="DflHelpInstaller"/>
</Feature>

CustomAction:

   public class CustomActions
   { 
        [CustomAction]
        public static ActionResult RegisterDflHelp(Session session)
        {
            session.Log("Begin CustomAction1");
            session.Log("Before Access to customactiondata");
 
            //should contain the installation path - unfortunately it is empty! why?
            string cad = session["CustomActionData"];
            Debugger.Break();


            RegisterHelp(cad);

            session.Log("End of custom action..");
            return ActionResult.Success;
        }
Continence answered 1/12, 2009 at 9:1 Comment(0)
U
20

If you delineate your data like ...

<CustomAction Id="MyCustomActionData" Return="check" Property="MyCustomAction" Value='PROPERTY0=[PROPERTY0];PROPERTY1=[PROPERTY1];PROPERTY2=[PROPERTY2]' Execute='immediate' />

You can access the data like:

string property0 = session.CustomActionData["Property0"];
string property1 = session.CustomActionData["Property1"];
string property2 = session.CustomActionData["Property2"];

In the previous example you would use:

<CustomAction Id="RegisterDflHelp.SetProperty" Return="check" Property="RegisterDflHelp" Value='INSTALLLOCATION=[INSTALLLOCATION]' Execute='immediate' />

then

string cad = session.CustomActionData["INSTALLLOCATION"];
Unroot answered 22/3, 2010 at 21:52 Comment(1)
I had to reference the properties with the same upper case property name (for example, session.CustomActionData["PROPERTY0"]).Kahlil
D
9

I accomplished this using the following in the .WXS file:

<Directory Id="TARGETDIR" Name="SourceDir">
 <Directory Id="ProgramFilesFolder" Name="PFiles">
  <Directory Id="ManufacturerDir" Name="Company" ShortName="Company">
   <Directory Id="INSTALLDIR" Name="TheApp">
    <Directory Id="BatchFileLocation" Name="BatchFiles">
     <Component Id="BatchFilesComp" ... >
      <File Id="SomeFile_BAT" Source="BatchFiles\SomeFile.bat" Name="SomeFile.bat" ... />
     </Component>
    </Directory>
   </Directory>
  </Directory>
 </Directory>
</Directory>

And in the custom Action:

var batchDirectory = session.GetTargetPath("BatchFileLocation");
var batchFile = batchDirectory + "SomeFile.bat"

Now, I haven't yet figured out how to avoid the duplication of the filename, but this does successfully return where the batch file was installed.

Discomposure answered 6/5, 2010 at 19:52 Comment(0)
C
5

After several hours of struglling, the following worked for me:

string UserDefinedInstallDir = session["INSTALLDIR"];

Hope it helps somenone else!

Chev answered 29/5, 2014 at 22:9 Comment(0)
R
2

Your passing the value correctly but try this way to reference it.

        string[] keys = new string[session.CustomActionData.Keys.Count];
        session.CustomActionData.Keys.CopyTo(keys, 0);
        string cad = keys[0];

This should set cad to the installation path like you want it.

Ratline answered 30/12, 2009 at 21:1 Comment(0)
C
1

Have you tried querying the INSTALLLOCATION property directly from within the managed CA?

string cad = session["INSTALLLOCATION"];

One of the beauties of using DTF is that you have read/write access to all the MSI properties without having to use command-lines etc. So even if INSTALLLOCATION cannot be queried like a normal property you could define your own MSI property set it to the value of INSTALLOCATION and query that one inside your CA instead.

Changchangaris answered 7/12, 2009 at 14:12 Comment(1)
Not if it's an "deferred" sequence, which is what he is doing. Only handful properties are available in deferred sequence.Engrave
P
0

In order to add a new property to the Session object :

public static ActionResult CustomAction1(Session session)

with the installation directory path for example :

<Directory Id="ProgramFiles64Folder" Name="name">
            <Directory Id="INSTALLDIR" Name="name1">

Just add a new CustomAction of type property :

<CustomAction Id="CustomAction1.SetProperty" Return="check" Property="INSTALLDIR_PROP" Value='[INSTALLDIR]' Execute='immediate' />

And add a new InstallExecuteSequence

<Custom Action='CustomAction1.SetProperty' After='CostFinalize' />

Then in the code you access this new property like this :

public static ActionResult CustomAction1(Session session)
{
        session.Log("MY NEW ADDED PROPERTY " + session["INSTALLDIR_PROP"]);

        return ActionResult.Success;
}
Provender answered 26/4, 2022 at 7:24 Comment(0)
D
0

Example for WixSharp:

[CustomAction]
public static ActionResult RunAfterInstall(Session session)
{
    System.Diagnostics.Process process = new();
    process.StartInfo.FileName = string.Format("{0}\\{1}", session["INSTALLDIR"], $"\\{Definitions.AppName}.exe");
    //process.StartInfo.FileName = @$"%ProgramFiles%\{Definitions.AppName}";
    process.StartInfo.Arguments = "--start-notification";
    //process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
    process.Start();

    return ActionResult.Success;
}
Dedicate answered 18/10, 2023 at 12:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.