Friday, May 6, 2011

How do I pass msiexec properties to a Wix C# custom action

I have an MSI being created with Wxs 3.0. My MSI references a C# custom action, written using the new C# Custom Action project (http://blogs.msdn.com/jasongin/archive/2008/05/23/custom-action-project-templates.aspx)

I want to pass an argument to msiexec that gets routed to my custom action - eg:

msiexec /i MyApp.msi ENVIRONMENT=TEST#

In my Wxs, I refer to my custom action like this:

<Property Id="ENVIRONMENT"/>
<Binary Id="WixCustomAction.dll"  SourceFile="$(var.WixCustomAction.Path)" />
<CustomAction Id="WixCustomAction" BinaryKey="WixCustomAction.dll"    DllEntry="ConfigureSettings"/>
<InstallExecuteSequence>
   <Custom Action="WixCustomAction" After="InstallFiles"></Custom>
</InstallExecuteSequence>

My C# custom action is setup like this:

[CustomAction]
public static ActionResult ConfigureSettings(Session session)
{

}

I was expecting to be able to access the property like this:

string environmentName = session.Property["ENVIRONMENT"];

but this doesn't seem to work.

How do I access the propery I passed to msiexec in my custom action?

From stackoverflow
  • Your CA needs to be a deferred CA in order to run after InstallFiles. Deferred CA's do not have access to properties, but they do have access to CustomActionData. See this blog post for a discussion on how to get what to do about it. (this example is a VBScript CA, but you will be able to retrieve the value through the session.CustomActionData collection)

  • Just for completeness; utilising the method described by Jeremy Lew, in the blog above allows for the following:

    Calling:

    msiexec /i ITP.Platform.2.msi ENVIRONMENT=QA CONFIGFILE=EnvironmentConfig.xml
    

    With this in the Wxs:

    <Property Id="ENVIRONMENT" Secure="yes" />
    <Property Id="CONFIGFILE" Secure="yes" />
    <Binary Id="Itp.Configurator.WixCustomAction.dll" SourceFile="$(var.Itp.Configurator.WixCustomAction.Path)" />
     <CustomAction Id="SetCustomActionDataValue" Return="check" 
          Property="Itp.Configurator.WixCustomAction" Value="[ENVIRONMENT],G2,[CONFIGFILE],[TARGETDIR]ITP_v$(var.VERSION_MAJOR)" />  
    
    <CustomAction Id="Itp.Configurator.WixCustomAction" Return="check" Execute="deferred"
          BinaryKey="Itp.Configurator.WixCustomAction.dll" DllEntry="ConfigureItpBrandSettings" />
     <InstallExecuteSequence>
       <Custom Action="SetCustomActionDataValue" After="InstallFiles"></Custom>
       <Custom Action="Itp.Configurator.WixCustomAction" After="SetCustomActionDataValue"></Custom>
     </InstallExecuteSequence>
    

    With custom action:

        /// <summary>
        /// CustomAction keys should be Environment,BrandId,ConfigPath,itpBasePath
        /// </summary>
        /// <param name="session"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult ConfigureItpBrandSettings(Session session)
        {
            string[] arguments = GetCustomActionDataArguments(session);
    
            string environmentName = arguments[0];
            string brandId = arguments[1];
            string configPath = arguments[2];
            string itpBasePath = arguments[3];
    
      //Do stuff
    
            return ActionResult.Success;
        }
    
        private static string[] GetCustomActionDataArguments(Session session)
        {
            string[] keys = new string[session.CustomActionData.Keys.Count];
            session.CustomActionData.Keys.CopyTo(keys,0);
            return keys[0].Split(',');
        }
    

    works.

    Parsing the CustomActionData arguments is pretty ugly, but it does work. - hopefully someone knows a more elegant way to do this.

  • If instead of

    <CustomAction Id="SetCustomActionDataValue" Return="check" Property="Itp.Configurator.WixCustomAction" Value="[ENVIRONMENT],G2,[CONFIGFILE],[TARGETDIR]ITP_v$(var.VERSION_MAJOR)" />
    

    you write this:

    <CustomAction Id="SetCustomActionDataValue" Return="check" Property="Itp.Configurator.WixCustomAction" Value="Environment=[ENVIRONMENT];G=G2;ConfigFile=[CONFIGFILE];TargetDir=[TARGETDIR]ITP_v$(var.VERSION_MAJOR)" />
    

    then you will be able to reference your variables like this:

    string env=session.CustomActionData["Environment"];
    

0 comments:

Post a Comment