Alex Shevchuk

Always listen to experts. They’ll tell you what can’t be done, and why. Then do it. - Lazarus Long

From MSI to WiX, Part 5 - Custom actions: Introduction

From MSI to WiX, Part 5 - Custom actions: Introduction

  • Comments 5
  • Likes

The main page for the series is here.

 

Introduction

Although standard actions are sufficient to execute an installation in most cases, custom actions enable the author of an installation package to extend the capabilities of standard actions by including executables, dynamic-link libraries, and script.

Important: Custom actions cannot be used in the sequence tables used for advertisement: AdvtUISequence and AdvtExecuteSequence tables.

Custom action types

Source\Type DLL Executable JScript VBScript Special
Binary table Type 1 Type 2 Type 5 Type 6  
Copied during installation Type 17 Type 18 Type 21 Type 22  
Referencing directory   Type 34      
Referencing property   Type 50 Type 53 Type 54  
Literal code in the database     Type 37 Type 38  
Error message         Type 19
Set directory with a formatted text         Type 35
Set property with a formatted text         Type 51

Deprecated concurrent installation actions

Concurrent Installations, also called Nested Installations, is a deprecated feature of the Windows Installer. Do not use concurrent installations to install products that are intended to be released to the public.

Custom action type Description
Type 7 Concurrent installation of a product residing in the installation package.
Type 23 Concurrent installation of an installer package within the current source tree.
Type 39 Concurrent installation of an advertised installer package.

Execution scheduling options

Because a custom action can be scheduled in both the UI and execute sequence tables, and can be executed either in the service or client process, a custom action can potentially execute multiple times.

This table describes the bit flags in the Type column of the CustomAction table and their meaning:

Bit flags <CustomAction> attribute Description
0 (default) Execute="immediate" Always execute. Action may run twice if present in both sequence tables.
msidbCustomActionTypeFirstSequence (0x100) Execute="firstSequence" Execute once if present in both sequence tables. Skips action in execute sequence if UI sequence has run. No effect in UI sequence. Not affected by install service registration.
msidbCustomActionTypeOncePerProcess (0x200) Execute="oncePerProcess" Execute once per process if in both sequence tables. Skips action in execute sequence if UI sequence has been run in same process, for example both run in the client process. Used to prevent actions that modify the session state, such as property and database data, from running twice.
msidbCustomActionTypeClientRepeat (0x300) Execute="secondSequence" Execute only if running on client after UI sequence has run. The action runs only if the execute sequence is run on the client following UI sequence. May be used to provide either/or logic, or to suppress the UI-related processing if already done for the client session.

Hidden Target option

Use the following option flags to specify that the installer not write the value entered into the Target field of the CustomAction table into the log.

Bit flags <CustomAction> attribute Description
0 (default) HideTarget="no" The installer may write the value in the Target column of the CustomAction table into the log file.
msidbCustomActionTypeHideTarget (0x2000) HideTarget="yes" The installer is prevented from writing the value in the Target column of the CustomAction table into the log file.
The CustomActionData property is also not logged when the installer executes the custom action.
Because the installer sets the value of CustomActionData from a property with the same name as the custom action, that property must be listed in the MsiHiddenProperties property to prevent its value from appearing in the log.

In-script execution options

You can use the following option flags to specify the in-script execution of custom actions. These options copy the action code into the execution, rollback, or commit script.

Note that the msidbCustomActionTypeInScript must be included with each of these options.

Bit flags <CustomAction> attribute Description
0 (default) Execute="immediate" Immediate custom action. Always runs in the user’s context.
msidbCustomActionTypeInScript (0x400) Execute="deferred" Deferred custom action.
msidbCustomActionTypeRollback (0x100) Execute="rollback" Rollback custom action.
msidbCustomActionTypeCommit (0x200) Execute="commit" Commit custom action.
msidbCustomActionTypeNoImpersonate (0x800) Impersonate="yes" Custom action runs in the system context.
msidbCustomActionTypeTSAware (0x4000) TerminalServerAware="yes" Per-machine installs on Terminal Server machines will be performed in the user's context.

Return processing options

The flags are used to specify that the main and custom action threads run synchronously (Windows Installer waits for the custom action thread to complete before resuming the main installation thread), or asynchronously (Windows Installer runs the custom action simultaneously while the main installation continues).

Bit flags <CustomAction> attribute Description
0 (default) Return="check" A synchronous execution that fails if the exit code is not 0 (zero).
msidbCustomActionTypeContinue
(0x40)
Return="ignore" A synchronous execution that ignores exit code and continues.
msidbCustomActionTypeAsync
(0x80)
Return="asyncWait" An asynchronous execution that waits for exit code at the end of the sequence.
This option cannot be used with Rollback and Script custom actions.
msidbCustomActionTypeAsync +
msidbCustomActionTypeContinue
(0x0C0)
Return="asyncNoWait" An asynchronous execution that does not wait for completion.
Execution continues after Windows Installer terminates.
This option can only be used with the EXE type custom actions.
All other types of custom actions can be asynchronous only within the install session, and must end for the installation to terminate.

Custom Action return values

The following error codes can be returned from the DLL custom action.  For EXE custom actions zero value means success and any other value indicates an error.

Return value Numeric value Description
ERROR_FUNCTION_NOT_CALLED 1626 Action not executed.
ERROR_SUCCESS 0 Completed actions successfully.
ERROR_INSTALL_USEREXIT 1602 User terminated prematurely.
ERROR_INSTALL_FAILURE 1603 Unrecoverable error occurred.
ERROR_NO_MORE_ITEMS 259 Skip remaining actions, not an error.

Scripting Custom Action return values

Scripting custom actions must return one of the following return codes:

Return Value Value Decsription
msiDoActionStatusNoAction 0 Action not executed.
msiDoActionStatusSuccess IDOK = 1 Action completed successfully.
msiDoActionStatusUserExit IDCANCEL = 2 Premature termination by user.
msiDoActionStatusFailure IDABORT = 3 Unrecoverable error. Returned if there is an error during parsing or execution of the Jscript or VBScript.
msiDoActionStatusSuspend IDRETRY = 4 Suspended sequence to be resumed later.
msiDoActionStatusFinished IDIGNORE = 5 Skip remaining actions. Not an error.

Custom Action Type 1

Calls a dynamic link library written in C/C++ which is stored in the Binary table.

The Source column in the CustomAction table contains the key to the record in the Binary table.

The DLL is called through the entry point named in the Target column of the CustomAction table.

All return processing, execution scheduling, and in-script execution options apply.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 1 custom action in Wix:

<Binary Id="MyCA" SourceFile="MyCA.dll"/>

 

<CustomAction Id="DoSomething"

              BinaryKey="MyCA"

              DllEntry="DoFunction"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence>

First, we add MyCA.dll to the Binary table.

We also add a custom action of Type 1 to the CustomAction table.  BinaryKey attribute points to the <Binary> element with the custom action dll.  DllEntry attribute specifies the name of the entry point function in the dll.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 2

Calls an executable stored in the Binary table.

The Source column in the CustomAction table contains the key to the record in the Binary table.

The Target column in the CustomAction table contains the command line string for the executable.

All return processing, execution scheduling, and in-script execution options apply.

Here is how to add Type 2 custom action in Wix:

<Binary Id="MyCA" SourceFile="MyCA.exe"/>

 

<CustomAction Id="DoSomething"

              BinaryKey="MyCA"

              ExeCommand="-switch"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence>

First, we add MyCA.exe to the Binary table.

We also add a custom action of Type 2 to the CustomAction table.  BinaryKey attribute points to the <Binary> element with the custom action dll.  ExeCommand attribute specifies the command line string for the executable.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 5

Calls the JScript custom action stored in the Binary table.

The Target column in the CustomAction table contains the optional script function to execute.

All return processing, execution scheduling, and in-script execution options apply.

All scripting custom actions require the installation of the Session object.  During execution of deferred custom action, Session object may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 5 custom action in Wix:

<Binary Id="MyCA" SourceFile="MyCA.js"/>

 

<CustomAction Id="DoSomething"

              BinaryKey="MyCA"

              JScriptCall="Main"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence> 

First, we add MyCA.js to the Binary table.

We also add a custom action of Type 5 to the CustomAction table.  BinaryKey attribute points to the <Binary> element with the custom action dll.  JScriptCall attribute specifies the script function to execute.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 6

Calls the VBScript custom action stored in the Binary table.

The Target column in the CustomAction table contains the optional script function to execute.

All return processing, execution scheduling, and in-script execution options apply.

All scripting custom actions require the installation of the Session object.  During execution of deferred custom action, Session object may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 6 custom action in Wix:

<Binary Id="MyCA" SourceFile="MyCA.vbs"/>

 

<CustomAction Id="DoSomething"

              BinaryKey="MyCA"

              VBScriptCall="Main"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence> 

First, we add MyCA.vbs to the Binary table.

We also add a custom action of Type 6 to the CustomAction table.  BinaryKey attribute points to the <Binary> element with the custom action dll.  VBScriptCall attribute specifies the script function to execute.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 17

Calls a dynamic link library written in C/C++ which is installed with the application during current session.

The Source column in the CustomAction table contains the key to the record in the File table.

The DLL is called through the entry point named in the Target column of the CustomAction table.

All return processing, execution scheduling, and in-script execution options apply.

Because file is installed with the application, there are sequencing restrictions on custom action Type 17:

  • If the source file is not already installed on the computer:
    • Custom action must be sequenced after CostFinalize action because only after this action path to the file can be resolved.
  • If the source file is not already installed on the computer:
    • Deferred custom actions of this type must be sequenced after the InstallFiles action.
    • Non-deferred custom actions of this type must be sequenced after the InstallFinalize action.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 17 custom action in Wix:

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

  <Component Id="Component1"

             Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

    <File Id="MyCA" Name="MyCA.dll" />

  </Component>

</Directory>

 

<CustomAction Id="DoSomething"

              FileKey="MyCA"

              DllEntry="DoFunction"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence>

First, we add MyCA.dll to the File table.

We also add a custom action of Type 17 to the CustomAction table.  FileKey attribute points to the <File> element with the custom action dll.  DllEntry attribute specifies the name of the entry point function in the dll.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 18

Calls an executable which is installed with the application during current session.

The Source column in the CustomAction table contains the key to the record in the File table.

The Target column in the CustomAction table contains the command line string for the executable.

All return processing, execution scheduling, and in-script execution options apply.

Because file is installed with the application, there are sequencing restrictions on custom action Type 18:

  • If the source file is not already installed on the computer:
    • Custom action must be sequenced after CostFinalize action because only after this action path to the file can be resolved.
  • If the source file is not already installed on the computer:
    • Deferred custom actions of this type must be sequenced after the InstallFiles action.
    • Non-deferred custom actions of this type must be sequenced after the InstallFinalize action.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 18 custom action in Wix:

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

  <Component Id="Component1"

             Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

    <File Id="MyCA" Name="MyCA.exe" />

  </Component>

</Directory>

 

<CustomAction Id="DoSomething"

              FileKey="MyCA"

              ExeCommand="-switch"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence>

First, we add MyCA.exe to the File table.

We also add a custom action of Type 18 to the CustomAction table.  FileKey attribute points to the <File> element with the custom action dll.  ExeCommand attribute specifies the command line string for the executable.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 19

This custom action displays a specified error message, returns failure, and then terminates the installation.

The value of columns in the CustomAction table:

  • Source:  must be blank.
  • Target:  Contains possibly formatted text which will be evaluated to the error message:
    • Text which is not enclosed in square brackets:
      • Text evaluates to integer:  Used as an index to the record in the Error table with the error message.
      • Contains the error message.
    • Text in square brackets will be evaluated further:
      • [Property]
      • [%EnvironmentVariable]
      • [#FilePath]
      • [$ComponentDirectoryPath]

None of the return processing, execution scheduling, and in-script execution options apply.

Here is an example of custom action Type 19 in Wix:

<CustomAction Id='IsPrivileged' Error='You must be an admin to install this product' />

 

<InstallExecuteSequence>

  <Custom Action='IsPrivileged' Before='LaunchConditions'>

    Not Privileged

  </Custom>

</InstallExecuteSequence>

Custom Action Type 21

Calls the JScript custom action which is installed with the application during current session.

The Source column in the CustomAction table contains the key to the record in the File table.

The Target column in the CustomAction table contains the optional script function to execute.

All return processing, execution scheduling, and in-script execution options apply.

Because file is installed with the application, there are sequencing restrictions on custom action Type 21:

  • If the source file is not already installed on the computer:
    • Custom action must be sequenced after CostFinalize action because only after this action path to the file can be resolved.
  • If the source file is not already installed on the computer:
    • Deferred custom actions of this type must be sequenced after the InstallFiles action.
    • Non-deferred custom actions of this type must be sequenced after the InstallFinalize action.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 21 custom action in Wix:

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

  <Component Id="Component1"

             Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

    <File Id="MyCA" Name="MyCA.js" />

  </Component>

</Directory>

 

<CustomAction Id="DoSomething"

              FileKey="MyCA"

              JScriptCall="Main"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence>

First, we add MyCA.js to the File table.

We also add a custom action of Type 21 to the CustomAction table.  FileKey attribute points to the <File> element with the custom action dll.  JScriptCall attribute specifies the script function to execute.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 22

Calls the VBScript custom action which is installed with the application during current session.

The Source column in the CustomAction table contains the key to the record in the File table.  The Target column in the CustomAction table contains the optional script function to execute.  All return processing, execution scheduling, and in-script execution options apply.

Because DLL is installed with the application, there are sequencing restrictions on custom action Type 22:

  • If the source file is not already installed on the computer:
    • Custom action must be sequenced after CostFinalize action because only after this action path to the file can be resolved.
  • If the source file is not already installed on the computer:
    • Deferred custom actions of this type must be sequenced after the InstallFiles action.
    • Non-deferred custom actions of this type must be sequenced after the InstallFinalize action.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 22 custom action in Wix:

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

  <Component Id="Component1"

             Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

    <File Id="MyCA" Name="MyCA.vbs" />

  </Component>

</Directory>

 

<CustomAction Id="DoSomething"

              FileKey="MyCA"

              VBScriptCall="Main"

              Execute="deferred"

              Return="check"

              HideTarget="no"

              Impersonate="no" />

 

<InstallExecuteSequence>

  <Custom Action="DoSomething" Before="InstallFinalize" />

</InstallExecuteSequence>

First, we add MyCA.vbs to the File table.

We also add a custom action of Type 22 to the CustomAction table.  FileKey attribute points to the <File> element with the custom action dll.  VBScriptCall attribute specifies the script function to execute.

The last thing to do is to schedule our custom action in all required sequence tables.

Custom Action Type 34

Calls an executable which already exists on the target system and is not installed with the application during current session.

The Source column in the CustomAction table contains the key to the record in the Directory table.  This record is used to resolve the full path to a working directory.  This is not required to be the path to the directory containing the executable.

The Target column in the CustomAction table contains the full path and name of the executable file followed by optional arguments to the executable.  The full path and name to the executable file is required. Quotation marks must be used around long file names or paths. The value is treated as formatted text and may contain references to properties, files, directories, or other formatted text attributes.

All return processing, execution scheduling, and in-script execution options apply.

Here is how to add Type 34 custom action in Wix:

<?xml version="1.0" encoding="UTF-8"?>

<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">

 

  <Product Id="{0BD4334D-F9FE-4B70-8070-917288A50B51}"

           Name="Minimal Windows Installer Sample"

           Language="1033"

           Codepage="1252"

           Version="1.0.0"

           Manufacturer="Acme Corporation"

           UpgradeCode="{770C5598-A538-4D44-8C2E-B2D94E15CC98}">

 

    <Package Id="{E1782FB0-3D87-4B13-88DC-62E11FB72552}"

             Description="Minimal Windows Installer Sample"

             Comments="This installer database contains the logic and data required to install [ProductName]."

             InstallerVersion="200"

             Languages="1033"

             SummaryCodepage="1252"

             Platforms="Intel"

             ReadOnly="no"

             Compressed="yes"

             AdminImage="no"

             Keywords="Installer"

             ShortNames ="no"

             Manufacturer="Acme Corporation" />

 

    <Media Id="1" Cabinet="CAB001.cab" EmbedCab="yes" />

 

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

      <Directory Id="ProgramFilesFolder">

        <Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">

 

          <Component Id="Component1"

                     Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

            <File Id="ReadMe" DiskId="1" Name="Readme.txt" Source="Readme.txt" Vital="yes" KeyPath="yes" />

          </Component>

 

        </Directory>

      </Directory>

    </Directory>

 

    <CustomAction Id="ShowReadMe"

                  Directory="INSTALLDIR"

                  ExeCommand="[SystemFolder]notepad.exe [#ReadMe]"

                  Return="asyncNoWait" />

 

    <InstallExecuteSequence>

      <Custom Action="ShowReadMe" After="InstallFinalize">Not Installed</Custom>

    </InstallExecuteSequence>

 

    <Feature Id="Feature1"

             Title="Feature1 title"

             Description="Feature1 description"

             Level="1"

             ConfigurableDirectory="INSTALLDIR" >

      <ComponentRef Id="Component1" />

    </Feature>

 

  </Product>

</Wix>

Here we are installing the ReadMe.txt file and using the custom action to show it's content in the notepad after installation is done.

Custom Action Type 35

Sets the target path and associated property of a record in the Directory table from a formatted text string.

The Source column in the CustomAction table contains the key to the record in the Directory table.

The Target column in the CustomAction table contains a formatted text and may contain references to properties, files, directories, or other formatted text attributes.

Only execution scheduling options apply.

Here is how to add Type 35 custom action in Wix:

<CustomAction Id="SetMergeModulesPath"

              Directory="MERGEDIR"

              Value="[ProgramFilesFolder]Common Files\Merge Modules" />

 

<InstallExecuteSequence>

  <Custom Action="SetMergeModulesPath" After="CostFinalize">Not Installed</Custom>

</InstallExecuteSequence>

Important:  Do not change the location of a target directory during maintenance installation.

Custom Action Type 37

Calls the JScript custom action stored internally in the CustomAction table.

The Source column in the CustomAction table contains the null value.

The Target column in the CustomAction table contains the script code for the custom action as a string of literal script text.

All return processing, execution scheduling, and in-script execution options apply.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 37 custom action in Wix:

<CustomAction Id="CopyReadMe"

              Script="jscript">

  <![CDATA[

  var fso = new ActiveXObject("Scripting.FileSystemObject");

  var path = Session.Property("INSTALLDIR");

  fso.CopyFile(path + "ReadMe.txt", path + "ReadMe2.txt");

  ]]>

</CustomAction>

 

<InstallExecuteSequence>

  <Custom Action="CopyReadMe" After="InstallFinalize">Not Installed</Custom>

</InstallExecuteSequence>

Custom Action Type 38

Calls the VBScript custom action stored internally in the CustomAction table.

The Source column in the CustomAction table contains the null value.

The Target column in the CustomAction table contains the script code for the custom action as a string of literal script text.

All return processing, execution scheduling, and in-script execution options apply.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 38 custom action in Wix:

<?xml version="1.0" encoding="UTF-8"?>

<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">

 

  <Product Id="{94A35E02-D48F-48F1-AC1A-23F62489BBF4}"

           Name="Minimal Windows Installer Sample"

           Language="1033"

           Codepage="1252"

           Version="1.0.0"

           Manufacturer="Acme Corporation"

           UpgradeCode="{74069BA4-1D1C-4252-A074-B2EC0C746403}">

 

    <Package Id="{????????-????-????-????-????????????}"

             Description="Minimal Windows Installer Sample"

             Comments="This installer database contains the logic and data required to install [ProductName]."

             InstallerVersion="200"

             Languages="1033"

             SummaryCodepage="1252"

             Platforms="Intel"

             ReadOnly="no"

             Compressed="yes"

             AdminImage="no"

             Keywords="Installer"

             ShortNames ="no"

             Manufacturer="Acme Corporation" />

 

    <Media Id="1" Cabinet="CAB001.cab" EmbedCab="yes" />

 

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

      <Directory Id="ProgramFilesFolder">

        <Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">

 

          <Component Id="Component1"

                     Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

            <File Id="ReadMe" DiskId="1" Name="Readme.txt" Source="Readme.txt" Vital="yes" KeyPath="yes" />

            <RemoveFile Id="RemoveCopy" Name="ReadMe2.txt" On="uninstall" />

          </Component>

 

        </Directory>

      </Directory>

    </Directory>

 

    <CustomAction Id="CopyReadMe"

                  Script="vbscript">

      <![CDATA[

      Set fso = CreateObject("Scripting.FileSystemObject")

      path = Session.Property("INSTALLDIR")

      fso.CopyFile path & "ReadMe.txt", path & "ReadMe2.txt"

      ]]>

    </CustomAction>

 

    <InstallExecuteSequence>

      <Custom Action="CopyReadMe" After="InstallFinalize">Not Installed</Custom>

    </InstallExecuteSequence>

 

    <Feature Id="Feature1"

             Title="Feature1 title"

             Description="Feature1 description"

             Level="1"

             ConfigurableDirectory="INSTALLDIR" >

      <ComponentRef Id="Component1" />

    </Feature>

 

  </Product>

</Wix>

Custom Action Type 50

Calls an executable launched with a command line.  Path and file name of the executable is stored in the property.  Typical use for this custom action is to find the installation path for the executable using registry search first.

The Source column in the CustomAction table contains a key to the Property table for a property that contains the full path to the executable file..

The Target column in the CustomAction table contains the command line string for the executable identified in the Source column.

All return processing, execution scheduling, and in-script execution options apply.

Here is how to add Type 50 custom action in Wix:

<!-- Find Zune's installation path -->

<Property Id="ZUNEFOLDER">

  <RegistrySearch Id="ZuneReg"

                  Root="HKLM"

                  Key="SOFTWARE\Microsoft\Zune"

                  Name="Installation Directory"

                  Type="raw" />

</Property>

 

<!-- Set the property to the <path>\Zune.exe -->

<CustomAction Id="SetZunePath"

              Property="ZunePath"

              Value="[ZUNEFOLDER]Zune.exe" />

 

<!-- Custom action to start the executable -->

<CustomAction Id="StartZune"

              Property="ZunePath"

              ExeCommand=""

              Return="asyncNoWait" />

 

<InstallExecuteSequence>

  <Custom Action="SetZunePath" After="AppSearch">ZUNEFOLDER</Custom>

  <Custom Action="StartZune" After="InstallFinalize">ZUNEFOLDER And Not Installed</Custom>

</InstallExecuteSequence>

Custom Action Type 51

Sets  the property's value from a formatted text string.

Replaceable parameters in the formatted text string are enclosed in the square brackets:

  • [...] - Property
  • [%...] - Environment variable
  • [#...] - File path
  • [$...] - Component directory path 

Only execution scheduling options apply.

Here is how to add Type 51 custom action in Wix:

<!-- Find Zune's installation path -->

<Property Id="ZUNEFOLDER">

  <RegistrySearch Id="ZuneReg"

                  Root="HKLM"

                  Key="SOFTWARE\Microsoft\Zune"

                  Name="Installation Directory"

                  Type="raw" />

</Property>

 

<!-- Set the property to the <path>\Zune.exe -->

<CustomAction Id="SetZunePath"

              Property="ZunePath"

              Value="[ZUNEFOLDER]Zune.exe" />

Custom Action Type 53

Calls the JScript custom action stored in the property.

The Source column in the CustomAction table contains a property name or a key to the Property table for a property containing the script text.

The Target column in the CustomAction table contains an optional script function name to be called.

All return processing, execution scheduling, and in-script execution options apply.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 53 custom action in Wix:

<?xml version="1.0" encoding="UTF-8"?>

<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">

 

  <Product Id="{A28D84A5-1DFB-4F2F-8CB5-C2D7764C697F}"

           Name="Minimal Windows Installer Sample"

           Language="1033"

           Codepage="1252"

           Version="1.0.0"

           Manufacturer="Acme Corporation"

           UpgradeCode="{3E339FF5-0E8F-47F2-AB8B-3F800A46C69A}">

 

    <Package Id="{????????-????-????-????-????????????}"

             Description="Minimal Windows Installer Sample"

             Comments="This installer database contains the logic and data required to install [ProductName]."

             InstallerVersion="200"

             Languages="1033"

             SummaryCodepage="1252"

             Platforms="Intel"

             ReadOnly="no"

             Compressed="yes"

             AdminImage="no"

             Keywords="Installer"

             ShortNames ="no"

             Manufacturer="Acme Corporation" />

 

    <Media Id="1" Cabinet="CAB001.cab" EmbedCab="yes" />

 

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

      <Directory Id="ProgramFilesFolder">

        <Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">

 

          <Component Id="Component1"

                     Guid="{A77C5B06-132D-4884-8E17-EA10A83C812D}">

            <File Id="ReadMe" DiskId="1" Name="Readme.txt" Source="Readme.txt" Vital="yes" KeyPath="yes" />

            <RemoveFile Id="RemoveCopy" Name="ReadMe2.txt" On="uninstall" />

          </Component>

 

        </Directory>

      </Directory>

    </Directory>

 

    <Property Id="CopyProgram">

      <![CDATA[

      function main()

      {

        var fso = new ActiveXObject("Scripting.FileSystemObject");

        var path = Session.Property("INSTALLDIR");

        fso.CopyFile(path + "ReadMe.txt", path + "ReadMe2.txt");

      }

      ]]>

    </Property>

   

    <CustomAction Id="CopyReadMe"

                  JScriptCall="main"

                  Property="CopyProgram">

    </CustomAction>

 

    <InstallExecuteSequence>

      <Custom Action="CopyReadMe" After="InstallFinalize">Not Installed</Custom>

    </InstallExecuteSequence>

 

    <Feature Id="Feature1"

             Title="Feature1 title"

             Description="Feature1 description"

             Level="1"

             ConfigurableDirectory="INSTALLDIR" >

      <ComponentRef Id="Component1" />

    </Feature>

 

  </Product>

</Wix>

Custom Action Type 54

Calls the VBScript custom action stored in the property.

The Source column in the CustomAction table contains a property name or a key to the Property table for a property containing the script text.

The Target column in the CustomAction table contains an optional script function name to be called.

All return processing, execution scheduling, and in-script execution options apply.

Entry point to the custom action receives the handle to the installation session.  During execution of deferred custom action, session may no longer exist.  To get the value of properties use CustomActionData property.

Here is how to add Type 54 custom action in Wix:

<?xml version="1.0" encoding="UTF-8"?>

<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">

 

  <Product Id="{C02C2DF1-F74E-4C61-8D19-151D9E70D64B}"

           Name="Minimal Windows Installer Sample"

           Language="1033"

           Codepage="1252"

           Version="1.0.0"

           Manufacturer="Acme Corporation"

           UpgradeCode="{59F2FD01-3932-4F33-882B-6A6E1E2FE0CF}">

 

    <Package Id="{????????-????-????-????-????????????}"

             Description="Minimal Windows Installer Sample"

             Comments="This installer database contains the logic and data required to install [ProductName]."

             InstallerVersion="200"

             Languages="1033"

             SummaryCodepage="1252"

             Platforms="Intel"

             ReadOnly="no"

             Compressed="yes"

             AdminImage="no"

             Keywords="Installer"

             ShortNames ="no"

             Manufacturer="Acme Corporation" />

 

    <Media Id="1" Cabinet="CAB001.cab" EmbedCab="yes" />

 

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

      <Directory Id="ProgramFilesFolder">

        <Directory Id="INSTALLDIR" Name="Minimal" LongName="MinimalInstallation">

 

          <Component Id="Component1"

                     Guid="{EB3E1A26-CA6C-4143-BCFA-C9CD8BFD363C}">

            <File Id="ReadMe" DiskId="1" Name="Readme.txt" Source="Readme.txt" Vital="yes" KeyPath="yes" />

            <RemoveFile Id="RemoveCopy" Name="ReadMe2.txt" On="uninstall" />

          </Component>

 

        </Directory>

      </Directory>

    </Directory>

 

    <Property Id="CopyProgram">

      <![CDATA[

      Function Main()

        Set fso = CreateObject("Scripting.FileSystemObject")

        path = Session.Property("INSTALLDIR")

        fso.CopyFile path & "ReadMe.txt", path & "ReadMe2.txt"

        Main = 1

      End Function

      ]]>

    </Property>

   

    <CustomAction Id="CopyReadMe"

                  VBScriptCall="Main"

                  Property="CopyProgram" />

 

    <InstallExecuteSequence>

      <Custom Action="CopyReadMe" After="InstallFinalize">Not Installed</Custom>

    </InstallExecuteSequence>

 

    <Feature Id="Feature1"

             Title="Feature1 title"

             Description="Feature1 description"

             Level="1"

             ConfigurableDirectory="INSTALLDIR" >

      <ComponentRef Id="Component1" />

    </Feature>

 

  </Product>

</Wix>

Comments
  • Hi Alex,

    I'm trying to get a custom action type 2 working but it keeps failing with error 1721. Do you have any idea why this is? Here is my code.

    Thanks in advance.

    <Binary Id="MyCA" SourceFile="C:\temp\MyCA.bat"/>

    <CustomAction Id="DoSomething" BinaryKey="MyCA" ExeCommand="" Execute="deferred" Return="check" Impersonate="no" />

    <InstallExecuteSequence>

     <Custom Action="DoSomething" After="InstallFiles" />

    </InstallExecuteSequence>

  • Usually, error 1721 means either problem with the script or some sort of permission issue.

    Your custom action is deferred, non-impersonated action, so it runs elevated under Local System account on Vista.

    Things I would check:

    - MyCA.bat is runnable outside of the installer (does not have any spelling/wrong commands issues)

    - Script in MyCA.bat does not access any network resources

    - Just in case, run installation from command prompt which is started under Administrator privileges

    - If you use Vista, try to turn off UAC

    - Try to disable anti-virus software (if computer is running any)

    Sorry, you will have to debug this issue.  There is no definite answer for this error code.

    Alex

  • Hm... I want to call this command line after installation:

    echo hello> echo_test.txt

    What should I do?

  • This article is excellent. Thanks much

  • Hi Alex, I am trying to execute database scripts either on SQL server or Oracle ( based on the Combo box item selection ) through WIX setup. When i tried to execute the scripts manually changing my Custom Action project to Console Application from Class Library everything goes fine but when i tried to do the same through setup its gave me the following error.

    "There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run."

    Below is Log Trace i got.

    Note: 1: 1723 2: VerifyConnection 3: VerifyConnection 4: C:\Users\adityak\AppData\Local\Temp\MSIC429.tmp

    Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor.  Action VerifyConnection, entry: VerifyConnection, library: C:\Users\adityak\AppData\Local\Temp\MSIC429.tmp

    MSI (c) (68:B4) [09:57:20:611]: Product: CRMnext -- Error 1723. There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor.  Action VerifyConnection, entry: VerifyConnection, library: C:\Users\adityak\AppData\Local\Temp\MSIC429.tmp

    Action ended 9:57:20: VerifyConnection. Return value 3.

    DEBUG: Error 2896:  Executing action VerifyConnection failed.

    The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2896. The arguments are: VerifyConnection, ,

    Any help??????

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment