InstallShield Tips and Techniques

July 14, 2007

Should you use CustomActionData?

Filed under: Reference Materials — shieldmaster @ 10:58 am

InstallShield 12 can be the bane of Deployment architects everywhere if there are existing MSI projects with InstallScript Custom Actions that need to be migrated to this new version!  All of their carefully worked Custom Action scripts created for earlier IS versions, will need to be re-evaluated after migrating to version 12.A severe problem that I have seen is that Custom Action written in InstallScript that are set to run Deferred will not have access to any MSI Property – there are very few exceptions, one MSI property accessable will be “CustomActionData”. So MSI Properties like “INSTALLDIR” and “PROGRAMFILES” are not accessible – no warning will be issues, just any attempt to retrieve data will result in a NULL value received.  Kind of destroys your script coding logic!

In my scripts, I tend to evaluate the workstation using InstallScript Custom Actions (Immediate Execution) and stash data in public MSI properties.  For example if I determine that Adobe Acrobat was installed, I store a boolean value (TRUE/FALSE) in an MSI Property, and the install path in another MSI Property.  Later when I want to launch the release notes, I have a InstallScript Custom Action set to Deferred to evaluate the MSI properties and take appropriate action.

With InstallShield 12 these InstallScript Custom Actions will no longer work correctly.  I will need to rework the Custom Action to store the data in the MSI Property CustomActionData.  Check out Christopher Painter’s blog notes on CustomActionData and its issues.  Normally the field would be used for a single value, but Christopher offers a technique to ‘stuff’ multiple values in the field for retrieval. 

Technically a great solution, but hard to implement and a bear in long term maintenance.I feel that there is a better solution for modifying existing/legacy scripts, simply by using the registry as your sandbox.  For example, take a section of the HKLM\SOFTWARE, which is normally suggested that you place specs on your Company Name (see entries for Adobe).  Use it as a sandbox and stash installation variables gleaned during the UI Sequence and later retrieve them during the Install Execute sequence.   Here is an example of the technique that I use:

Prime RegistryJust after the dialogs have completed create a InstallScript Custom Action that will allow you to gather up all of your special MSI Properties that were initialized during previous CA’s and write them to the registry.  Here is a script extract:

RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE ); 
szRegKey = “SOFTWARE\\Install Solutions\\Framework”; 
nvType = REGDB_STRING;

szRegSubKey =   “InstallDir”;
szProgramFilesDir = INSTALLDIR;
nResult = RegDBSetKeyValueEx(szRegKey, szRegSubKey, nvType, szInstallDir,-1);
if (nResult < 0 )then
   szBuffer = “ISI–>  ERROR – szInstallDir Directory” + could not be updated in registry:  ‘%s'” ;
 Sprintf (szLogMessage, szBuffer, szRegKey);
 ISI_Fn_WriteLogFile (szLogMessage);      
else
 szBuffer = “ISI–>  INFO – szInstallDir Directory location ‘%s’ updated in registry: ‘%s’ with key of ‘%s’ “;
 Sprintf (szLogMessage, szBuffer, szInstallDir, szRegKey, szRegSubKey);
 ISI_Fn_WriteLogFile (szLogMessage);      
endif;   
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE ); 
szRegKey = “SOFTWARE\\Install Solutions\\Framework”; 
nvType = REGDB_STRING;

// Obtain MSI Property for CustomerName and update Registry
nBuffSize = 256;
szMSIProperty = “ISI_CUSTNAME”;
szRegSubKey   = “CustomerName”;
  MsiGetProperty (ISMSI_HANDLE, szMSIProperty, svValue, nBuffSize);
  //Update the CustomerName Key.
  nResult = RegDBSetKeyValueEx(szRegKey, szRegSubKey, nvType, svValue, -1);
 if (nResult < 0 )then
   szBuffer=”ISI–>  ERROR-MSI Property ‘%s’ could not be updated in registry:  ‘%s'” ;
  Sprintf (szLogMessage, szBuffer, szMSIProperty, szRegKey);
  ISI_Fn_WriteLogFile (szLogMessage);      
 else
  szBuffer=”ISI–>INFO-MSI Property ‘%s’ updated in registry: ‘%s’ w/value of ‘%s’ “;
  Sprintf (szLogMessage, szBuffer, szMSIProperty, szRegKey, svValue);
  ISI_Fn_WriteLogFile (szLogMessage);      
 endif;   

Retrieve Registry ValuesIn each InstallScript Custom Action, simply add this script at the beginning to retrieve the values from the registry and store them into variables.  It should flow seamlessly into your existing script – here is some sample script that I use:

nvSize=256;  

RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 

szKey=”SOFTWARE\\Install Solutions\\Framework”;nType=REGDB_STRING;  

//Get the InstallDir Key.

RegDBGetKeyValueEx(szKey,”InstallDir”, nType, svInstallDir, nvSize);     

szBuffer = “Retrieved from registry key ‘%s’ the InstallDir key which was ‘%s’ “;      Sprintf (szLogMessage, szBuffer, szKey, svInstallDir );     

ISI_Fn_WriteLogFile (szLogMessage);               

//Get the Customer Name.RegDBGetKeyValueEx(szKey,”ISI_CustName”,nType,szCustName,nvSize);     

szBuffer=”Retrieved from registry key ‘%s’ the ISI_CustName key which was ‘%s’ “;     

Sprintf (szLogMessage, szBuffer, szKey, szCustName );     

ISI_Fn_WriteLogFile (szLogMessage);    

After the install has been completed, should the install variables placed in the registry be deleted?  Not necessarily, it could have use in the uninstall process.  But remember to delete them when the uninstall has completed. 

Hope this helps! 

Charles  

1 Comment »

  1. Serializing datasets, as confusing as it is, is the MSI way of passing data from the Immediate to the Deferred context. The concept of using HKLM/Software to pass the data will fail during elevated installs on 2000/XP and will almost always fail on Vista with UAC enabled. The reason is that while the user has rights to elevate the install, the user isn’t actually expressing a privleged token for use during the immeadiate execution. The CA simply won’t have authority to write to that part of the registry. There is also the problem of rolling back the data from the registry.

    I wrote the helper functions as a way to simplify the data passing. I’ve also tossed around the idea of creating an XML document and passing it as the property. This would allow the deferred side to issue an XPath statement to look up the data elements. I havn’t done so through because 1) most people don’t need this level of complexity and 2) it adds an additional install dependency (msxml)

    Comment by Christopher Painter — July 17, 2007 @ 6:39 am


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.