I don't know the whole back story, and I'm sorry Jim feels that his work is going down the drain, but I only have one thing to say to this:
Hip Hip Hooray!!!!!
<Binary Id="CustomActionModeTest" SourceFile="PATH_TO_DLL.CA.dll " </Binary>
<CustomAction Id="RollbackCA" BinaryKey="CustomActionModeTest" DllEntry="CustomAction1" Execute="rollback" Impersonate="yes"> </CustomAction>
<CustomAction Id="DeferredCA" BinaryKey="CustomActionModeTest" DllEntry="CustomAction1" Execute="deferred" Impersonate="yes"> </CustomAction>
<InstallExecuteSequence>
<Custom Action="RollbackCA" After="InstallInitialize"> </Custom>
<Custom Action="DeferredCA" After="RollbackCA"> </Custom>
</InstallExecuteSequence>
using System; using System.Windows.Forms; using Microsoft.Deployment.WindowsInstaller; namespace CustomActionModeTest { public class CustomActions
{ [CustomAction]
public static ActionResult CustomAction1(Session session)
{ ActionResult result = ActionResult.Success;
if (session.GetMode(InstallRunMode.Scheduled)) { MessageBox.Show("I'm not in rollback, let's cause one to occur!"); result = ActionResult.Failure;
}
if (session.GetMode(InstallRunMode.Rollback)) { MessageBox.Show("We are now in a rollback." ); }
return result; }
}
}
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <MsiQuery.h>
/////////////////////////////////////////////////////////// // ICE01 - simple ICE that does not test anything UINT __stdcall ICE01(MSIHANDLE hInstall)
{ // setup the record to describe owner and date created PMSIHANDLE hRecCreated = ::MsiCreateRecord(1);
::MsiRecordSetString(hRecCreated, 0, TEXT("ICE01\t3\tCreated 04/29/1998 by <insert author's name here>")); // post the owner message ::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecCreated);
// setup the record to describe the last time the ICE was modified ::MsiRecordSetString(hRecCreated, 0, TEXT("ICE01\t3\tLast modified 05/06/1998 by <insert author's name here>")); // post the last modification message ::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecCreated);
// setup the record to describe what the ICE evaluates ::MsiRecordSetString(hRecCreated, 0, TEXT("ICE01\t3\tSimple ICE illustrating the ICE concept")); // post the description of evaluation message ::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecCreated);
// time value to be sent on TCHAR szValue[200];
DWORD cchValue = sizeof(szValue)/sizeof(TCHAR);
// try to get the time of this call if (MsiGetProperty(hInstall, TEXT("Time"), szValue, &cchValue) != ERROR_SUCCESS)
StringCchCopy(szValue, sizeof("(none)")/sizeof(TCHAR)+1, TEXT("none"));// no time available
// setup the record to be sent as a message PMSIHANDLE hRecTime = ::MsiCreateRecord(2);
::MsiRecordSetString(hRecTime, 0, TEXT("ICE01\t3\tCalled at [1].")); ::MsiRecordSetString(hRecTime, 1, szValue);
// send the time ::MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_USER), hRecTime);
return ERROR_SUCCESS; // allows other ICEs will continue
}
using DE.TestFramework; using Microsoft.Deployment.WindowsInstaller; namespace DE.Tests { partial class ICE01 : TestBase
{ [ICETest]
public void TestExample()
{ Publish( ICELevel.Information, "Created 04/29/1998 by <insert author's name here>"); Publish( ICELevel.Information, "Last modified 05/06/1998 by <insert author's name here>"); Publish( ICELevel.Information, "Simple ICE illustrating the ICE concept"); Publish( ICELevel.Information, "Called at " + Session["Time"] );
}
}
}
public void Publish(ICELevel iceLevel, string Description)
public void Publish(ICELevel iceLevel, string Description, string HelpLocation )
public void Publish(ICELevel iceLevel, string Description, string HelpLocation, string Table, string Column, string PrimaryKey)
public void Publish(ICELevel iceLevel, string Description, string HelpLocation, string Table, string Column, string[] PrimaryKeys)
using DE.TestFramework; using Microsoft.Deployment.WindowsInstaller; using System; namespace DE.Tests { partial class ICE_DE_10
{ [ICETest]
public void TestForScriptCustomActionsAreEvil()
{ Publish(ICELevel.Information, "Searching for Evil Script Custom Actions..."); using (View view = Session.Database.OpenView("SELECT `CustomAction`.`Action`, `CustomAction`.`Type` FROM `CustomAction`"))
{ view.Execute();
foreach (var record in view)
{ string customActionName = record.GetString("Action");
int type = record.GetInteger("Type") & 0x00000007;
CustomActionTypes customActionType = (CustomActionTypes)type;
if (customActionType.Equals(CustomActionTypes.VBScript) || customActionType.Equals(CustomActionTypes.JScript)) { Publish(ICELevel.Error,
"Found Evil " + customActionType.ToString() + " Custom Action " + customActionName,
"http://blogs.msdn.com/robmen/archive/2004/05/20/136530.aspx", "CustomAction", "Action", customActionName );
}
else { Publish(ICELevel.Information, "Found Nice Custom Action: " + customActionName + " Type: " + customActionType.ToString());
}
}
}
}
}
}
If you do build under the scenario described above, then you should be aware that the options appear to be mutually exclusive and the custom CAB names you specified will NOT be generated correctly by InstallShield at build time.
Below is a description of the problem I reported to Acresso support yesterday (incident #SIOA-000140045):
I have a serious problem with the IsCmdBld.exe in InstallShield 2009 Premier that I need a fix for ASAP.
We are in the process of upgrading our build environment to use IS 2009 to build our primary application installation and are seeing different behavior during the build between the IsSABld.exe we used with previous versions of IS (both IS 12 Premier and IS 2008 Premier) and the behavior seen using IsCmdBld.exe in IS 2009 Premier.
Our primary application installation is a very complex and large MSI installation. Since we must control the names of the CAB files we generate at build time, we use the InstallShield Direct Editor to modify the Feature table in the InstallShield source project and specify a different CAB name for each defined feature (using the ISFeatureCabName field). Using the Release Wizard, we also set the Release Configuration to 'Custom' and select the "One .cab per Feature" option ("Custom Compression Settings" dialog of the Release Wizard). In addition, we specify the fully qualified path and name of a previous MSI package build (by setting the "Previous package" option on the "Advanced Settings" dialog of the Release Wizard. The only other configuration information that may be relevant to this issue is the fact that we have multiple merge modules in the project and each defined feature has one or more merge modules associated with it (no merge module is associated with more than one feature).
When we build the installation (with NO CHANGES other than upgrading the project to IS 2009 schema format) using the IsCmdBld.exe command line utility from IS 2009 the CAB files are not generated correctly. In other words, the files associated with feature A are not being placed into the CAB file specified in the ISFeatureCabName for feature A. However, if I remove the option to point the build to a previous package and then build the project then the CAB files are generated correctly (the files associated with feature A are being correctly placed into the CAB file specified in the ISFeatureCabName for feature A.
In other words, the options to specify the CAB file name for each feature (ISFeatureCabName column of the Feature table) and the Release Wizard option for Patch optimization ("Previous package" option) ARE MUTUALLY EXCLUSIVE IN IS 2009.
I have confirmed this behavior by building under the different scenarios described below:
In all scenarios specified above EXCEPT "Build E", the CAB files are correctly generated during the build. In other words, in each of the scenarios EXCEPT "Build E", the files associated with feature A are correctly placed into the CAB file whose name is specified in the ISFeatureCabName column of the Feature table.It is absolutely critical that this be fixed or we cannot use IS 2009 without completely redesigning our MSI installation packaging.