WiX: Passing Install path to managed custom action

21,552

Solution 1

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"];

Solution 2

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.

Solution 3

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

string UserDefinedInstallDir = session["INSTALLDIR"];

Hope it helps somenone else!

Solution 4

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.

Solution 5

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.

Share:
21,552
Admin
Author by

Admin

Updated on August 04, 2020

Comments

  • Admin
    Admin over 3 years

    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;
            }