How to prevent a registry key from being overwritten by a newer version of the package.

Installer software, free windows MSI creation tool
Home | Contact | Site Map |
Download Features Java Licensing Purchase Testimonials Support Forums FAQs
USER GUIDE

How do I prevent a registry key from being overwritten by a newer version of the package?

Answer

Sometimes, the registry entries on the target machine should not be replaced by the registry entries in your package. For example:

  • the entries contain a custom configuration for the application and they should not be overwritten by the default ones during an upgrade
  • the entries in your package overwrite entries which are already created; in this case the uninstall of the package will remove the entries completely

In order to avoid the replacement of the original entries you can use two custom actions: one for the backup of the registry entries and one for the restore. The backup custom action can be executed in the early stages of the install process, for example you can schedule it under the InstallExecuteSequence -> CostFinalize standard action. However, the restore custom action should be executed as late as possible, for example after InstallExecuteSequence -> InstallFinalize.

The backup and restore custom actions are basically the same and they have only one goal: copy the content of a registry key into another registry key. For example, here is a VBScript custom action which does this:

On Error Resume Next 
        
'set the registry hive used in the custom action
Const HKEY_LOCAL_MACHINE = &H80000002 
        
'set the main registry keys
strComputer = "."
command = Session.Property("CustomActionData")
tokens  = Split(command,"|")
source  = tokens(0)
target  = tokens(1)
        
'create an object which handles the registry operations
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_
strComputer & "\root\default:StdRegProv") 
        
'create the backup key	
objReg.CreateKey HKEY_LOCAL_MACHINE, target
        
'call the function which copies everything from the target key
CopyKey HKEY_LOCAL_MACHINE, source, target 
        
'the copy function
Sub CopyKey(HKEY_LOCAL_MACHINE, source, target) 
        
        'enumerate all subkeys of the main key
        objReg.EnumKey HKEY_LOCAL_MACHINE, source, SubKeysList
        
        'for each subkey call the copy function
        If IsArray(SubKeysList) Then 
        For Each SubKey In SubKeysList 
              'create the subkey in the backup key before calling the copy function for it
              objReg.CreateKey HKEY_LOCAL_MACHINE, target & "\" & SubKey
              CopyKey HKEY_LOCAL_MACHINE, source & "\" & SubKey, target & "\" & SubKey
        Next 
        End If 
        
        'enumerate the values in the current key
        objReg.EnumValues HKEY_LOCAL_MACHINE, source, ValueList, ValueTypes
        
        'copy each value to the corresponding backup key
        For i = 0 To UBound(ValueList)
              objReg.GetStringValue HKEY_LOCAL_MACHINE, source, ValueList(i), Value
              objReg.SetStringValue  HKEY_LOCAL_MACHINE, target, ValueList(i), Value
        Next
End Sub

This code can be pasted into a .VBS file. It uses the CustomActionData property which contains the values from the "Action Data" field in the Custom Action Properties page. This property is used to determine the source and the target keys. For example, the "Action Data" field in your project can look like this:

Software\MyKey|Software\MyKey_Backup

This means that the source will be the first string before the "|" character (Software\MyKey) and the target will be the string which comes after the "|" character (Software\MyKey_Backup).

NoteThe above code can be used as a backup custom action and it should copy the original key to a new one. Also, you can use it as a restore custom action by changing the "Action Data" field.

After the restore is performed, there is no need for the backup key, therefore it can be deleted. Here is a VBScript custom action which does this:

On Error Resume Next 
        
'set the registry hive used in the custom action        
Const HKEY_LOCAL_MACHINE = &H80000002 
        
strComputer = "."
key = Session.Property("CustomActionData") 
        
'create an object which handles the registry operations
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_
strComputer & "\root\default:StdRegProv")
        
'call the function which deletes the key
DeleteKey HKEY_LOCAL_MACHINE, key
        
        ' the delete function        
        Sub DeleteKey(HKEY_LOCAL_MACHINE, key) 
        'enumerate all subkeys of the main key
        objReg.EnumKey HKEY_LOCAL_MACHINE, key, SubKeysList
        
        'for each subkey call the delete function
        If IsArray(SubKeysList) Then 
        For Each SubKey In SubKeysList
              DeleteKey HKEY_LOCAL_MACHINE, key & "\" & SubKey
        Next 
        End If 
        
        'delete the current key
        objReg.DeleteKey HKEY_LOCAL_MACHINE, key
End Sub

ImportantThe custom action which deletes the backup key should be launched only after the restore custom action runs.

The key which will be deleted is also set through the "Action Data" field. Inside the custom action, the path of the key will be retrieved from the CustomActionData property.

NoteBy using the "Action Data" field the custom actions become generic (they can be used for any keys you want). Also, these custom actions can runs as "Deferred with no impersonation" on Windows Vista.

© 2002 - 2008 Caphyon Ltd. Trademarks belong to their respective owners. All rights reserved.