Running Windows Installer packages that are major upgrade (changing product version and product code) against the assemblies placed in the GAC en the assemblies version is not changed, will result in deleting assemblies without re-installing them. See http://support.microsoft.com/kb/905238 for details.

The following conditions must be met to observe the issue:

1)       Create the Visual Studio Setup and Deployment project that places target assembly ((assemblies) into GAC

2)       Set RemovePreviousVersion property of the Setup project to true.

3)       Compile MSI package and run it once (e.g. with default product version 1.0.0)

4)       Increase the product version (e.g. to 2.0.0). This will result in changing the product code. Run the MSI package.

5)       The previously installed into GAC assembly (assemblies) will be removed after running step 4.

 

To prevent this behavior one of 3 approaches should be followed:

1)       Increase the AssemblyVersion attribute of the assembly that you are upgrading the GAC. This must used only if you have reasons to change the version (changes to functionality or bug fixes) as it may break the dependent assemblies

2)       Use a Windows Installer table-authoring tool to change the sequencing of the RemoveExistingProducts action in the InstallExecuteSequence table to occur after the InstallFinalize action. For example, use the Orca.exe database table editor for creating or editing Windows Installer packages. Orca is available as a part of the Platform SDK for Windows 2003 Server R2 (http://www.microsoft.com/downloads/details.aspx?FamilyId=0BAF2B35-C656-4969-ACE8-E4C0C0716ADB&displaylang=en)

3)       Use the Windows Installer API (through the script or PInvoke) to change the sequence of RemoveExistingProducts and InstallFinalize in InstallExecuteSequence table. The sample script is presented below. This script must be executed in the post-build event of the setup project against the targeted MSI file. Also I would recommend the good introduction to Windows Installer posted in the attached whitepaper.

===============================================================

Option Explicit

If (Wscript.Arguments.Count < 1) Then
Wscript.Echo "Windows Installer utility to execute SQL queries against an installer database." &_
vbLf & " The 1st argument specifies the path to the MSI database, relative or full path"
Wscript.Quit 1
End If

Dim openMode : openMode = 1 'msiOpenDatabaseModeTransact

On Error Resume Next

Dim installer : Set installer = Wscript.CreateObject("WindowsInstaller.Installer") : CheckError
' Open database
Dim database : Set database = installer.OpenDatabase(Wscript.Arguments(0), openMode) : CheckError

Wscript.Echo "Reading InstallFinalize sequence #..."

Dim query, record, rowData
query = "SELECT `Sequence` FROM `InstallExecuteSequence` WHERE `Action` = 'InstallFinalize'"
Dim view : Set view = database.OpenView(query) : CheckError
view.Execute : CheckError
Set record = view.Fetch
If record Is Nothing Then
 Wscript.Echo "InstallFinalize sequence # cannot be found."
 Wscript.Quit 1
Else
 rowData = record.IntegerData(1)
End If

Wscript.Echo "InstallFinalize sequence # = " & rowData

Wscript.Echo "Changing RemoveExistingProducts sequence to be last action..."

query = "UPDATE `InstallExecuteSequence` SET `Sequence` = " & rowData + 100 & " WHERE `Action` = 'RemoveExistingProducts' "
Set view = database.OpenView(query) : CheckError
view.Execute : CheckError
database.Commit
Wscript.Echo "Done."
Wscript.Quit 0

Sub CheckError
Dim message, errRec
If Err = 0 Then Exit Sub
message = Err.Source & " " & Hex(Err) & ": " & Err.Description
If Not installer Is Nothing Then
Set errRec = installer.LastErrorRecord
If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
End If
Wscript.Echo message
Wscript.Quit 2
End Sub