The "DllCa" Command |
This command is used to define and schedule a pre-existing DLL based custom action. It also sets up the "Action Text" which gets displayed in the progress bar.
Note that you can use the "DllCa-C" command to create the source for a C/C++ based DLL, compile, link and add to the MSI if you wish.
This command takes these parameters:
UINT __stdcall CustomAction(MSIHANDLE hInstall);
If you built the DLL with the "DllCa-C" command then you must use the "DllCaEntry?" command to refer to your entry point.
If your custom action fails, check that you have the correct case and "decorators" by opening the file in "Dependency Walker", MinGw's pexports.exe" or another tool which will list exports.
A non-blank value indicates the DLL runs from the "Binary" table. A value of "?" means allow this command to choose the key into the "Binary" table, any other value is the key itself.
To refer to an existing "Binary" key you should pass the key name in this parameter and the "DLL" parameter should be blank (as a non-blank "DLL" parameter means add the DLL to the "Binary" table).
Either this parameter or the "File" parameter must be used.
Note that "MSIEXEC.EXE" (version 4+, in Vista) is build with the "NXCOMPAT" option, this will be an issue if any of your code (or the libraries it uses) is not NX compliant. See "KB929710" for more information.
There will typically be a lot of standard actions at known fixed locations (which may however differ in sequence number or even order relative to one another with different templates). Click here for the default "InstallExecuteSequence" and "InstallUISequence" sequencing details.
Normally you try not to duplicate sequence numbers but it is probably OK to do so as long as you don't care which one executes first! One possible exception would be deferred custom actions where the custom action data needs to be setup before execution. You should get a validation message to indicate a duplicated number (note that validation can't know whether custom action conditions are mutually exclusive etc).
The sequencing information (see some default sequencing) can be supplied in a number of formats:
Basically you describe a range of valid values and whether you prefer the value to be chosen from the lower (default) or higher end.
The range should be specified in the format "lower - higher". Either value can be omitted, be specified as an integer such as "1000" or the name of an action such as "InstallFiles". The default value for the lower end is "1" and for the higher "32767" and leading and trailing spaces for each are stripped. The minimum and maximum values can be returned as the range is inclusive.
By default MAKEMSI will choose a number as close as possible to the lower end, if you wish it to be as high as possible then begin the specification string with "<".
Some Examples:
You should of course be aware of what your script does, for example if it moves a custom action that you have already sequenced other actions relative to then that would probably be "bad"!
Note that you can supply an empty list (no tables) if you just want to define the custom action but not sequence it, however you must confirm this by supplying a sequence number of 0 (zero) on the "SEQ" parameter can you should also supply "" for the "CONDITION" parameter (value ignored).
I have captured a large number of "sample properties" which could be used in any conditions. Note that the values of some properties may not be available at all times and in some cases are modified during processing.
You can also use any of the following predefined conditions:
#define? CONDITION_ALREADY_INSTALLED Installed ;;Repair, uninstall etc. #define? CONDITION_INSTALL_ONLY not Installed ;;Doesn't include a repair, uninstall etc! #define? CONDITION_UNINSTALL_ONLY Installed and REMOVE~="ALL" ;;Complete uninstall - HIGHLY RECOMMENDED at you read the "REMOVE" properties MAKEMSI doco! #define? CONDITION_EXCEPT_UNINSTALL not (<$CONDITION_UNINSTALL_ONLY>) ;;Install, Repair etc (all but complete uninstall) #define? CONDITION_IS_WIN2000 VersionNT = "500" ;;Is OS WIN2000? #define? CONDITION_IS_WINXP VersionNT = "501" ;;Is OS WINXP? #define? CONDITION_IS_VISTA VersionNT = "600" ;;Is OS WINDOWS Vista? #define? CONDITION_IS_WINDOWS_7 VersionNT = "601" ;;Is OS WINDOWS Windows7 #define? CONDITION_UI_NONE UILevel = 2 ;;Silent Install #define? CONDITION_UI_BASIC UILevel = 3 #define? CONDITION_UI_REDUCED UILevel = 4 #define? CONDITION_UI_FULL UILevel = 5 ;;"Normal" #define? CONDITION_UI_NO_DIALOGS UILevel <> 5 ;;Don't bother user with popup dialogs, opening readme files etc. #define CONDITION_PER_MACHINE Version9X or (ALLUSERS = 1) ;;True if per-machine install. #define CONDITION_PER_USER not (<$CONDITION_PER_MACHINE>) ;;True if per-user (not per-machine) install.
This parameter accepts one or more space separated attributes which are processed in left to right order. Available attributes are (not all may apply):
A deferred (in-script) custom action must be sequenced between the "InstallInitialize" and "InstallFinalize" actions (or you will get a 2762 error) and data is passed via the "CustomActionData" property.
All deferred actions are executed in a single pass by the server "MSIEXEC.EXE" service (a separate process) after being combined in a "script".
All immediate custom actions scheduled between the "InstallInitialize" and "InstallFinalize" actions (regardless of their sequence number) are executed before deferred ones.
This should only be used as a last resort when executing some poorly written piece of "cr*p" (or perhaps if it's success is not critical to the install).
Rollback custom actions (and so also the "worker" custom action) must be "deferred" and sequenced between "InstallInitialize" and "InstallFinalize".
There are circumstances where a custom action may still run with system privileges.
Lack of this attribute on deferred custom actions is a common reason for failures on Vista.
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.
If the number begins with "0x" (case insensitive) then the number is being supplied as a hexadecimal value otherwise its interpreted as being in decimal.
You may need to supply a numeric value such as "+0x0001" if I haven't provided a suitable alias above...
EXAMPLE - INSTALLED FILE |
The DLL used in this example can be obtained from "http://www.codeproject.com/KB/install/msicustomaction.aspx".
This example executes a DLL installed by this package:
;--- Add the file to the "File" Table --- <$File RowKey="DllAsInstalledFile" SOURCE="D:\DBAREIS\Projects\Win32\MAKEMSI_SAMPLE_DLL\CodeProject Sample.dll" Destination="[INSTALLDIR]\TestDll.DLL"> ;--- Now call "SampleFunction()" -------- <$DllCa File="DllAsInstalledFile" Seq="InstallFiles-" Entry="SampleFunction" Condition="<$DLLCA_CONDITION_INSTALL_ONLY>">
Obviously the custom action must be sequenced after the file is installed and before it is removed otherwise the DLL (or a copy) should be put into the binary table instead (see below).
EXAMPLE - BINARY TABLE |
The DLL used in this example can be obtained from "http://www.codeproject.com/KB/install/msicustomaction.aspx".
;--- Run 2 different DLL Entry Points --- <$DllCa Binary="DllInBinaryTable" SEQ="DeleteServices-" Entry="SampleFunction" Condition="<$DLLCA_CONDITION_INSTALL_ONLY>" DLL=^..\MAKEMSI_SAMPLE_DLL\CodeProject Sample.dll^> <$DllCa Binary="DllInBinaryTable" SEQ="DeleteServices-" Entry="SampleFunction3" Condition="<$DLLCA_CONDITION_INSTALL_ONLY>">