views:

94

answers:

2

Given an installer generated with a VS2010 Setup Project, I would like to swap out a .NET DLL with another one without changing the name.

I am already altering the msi file according to this question, swapping out the contents of an entry in the "Binary" table.

I have located the file in question using Orca. It resides in the only cabinet file. I have located this cabinet file in the "Media" table. I'm not sure how to change this cabinet file (API) and I suspect I'd have to change some information in the MSI database too (the "ProcessorArchitecture" record for the assembly in the "MsiAssemblyName" table).

Rationale: I'm making an installer for a Autodesk Revit 2011 plugin. These are registered using an assembly RevitAddinUtility.dll which must be bundled with the installer. This assembly comes in two flavors, one for 32-bit and one for 64-bit installations. I need to swap in the correct version when creating the installer, to avoid writing more than one installers.

A: 

Here is a workaround I'm using in the meantime:

  • add both files, one named RevitAddinUtility.dll the other RevitAddinUtility64.dll
  • in the PostBuild-Event, ask the user if the setup project should be for 64bit.
  • if yes, then change the names of the files:

    If 6 = MsgBox("Build for 64bit?", 4, "Setup PostBuild event for DesignPerformanceViewer") Then
        Dim installer : Set installer = Wscript.CreateObject("WindowsInstaller.Installer")
        Dim database : Set database = installer.OpenDatabase(PATH_TO_MSI, msiOpenDatabaseModeTransact)
        Dim sqlQuery : sqlQuery = "SELECT `FileName`, `Component_` FROM File"
        Dim view : Set view = database.OpenView(sqlQuery)
        view.Execute
        Dim record : Set record = view.Fetch
        While Not record Is Nothing        
            If InStr(record.StringData(1), "RevitAddInUtility.dll") Then  
                record.StringData(1) = "REVITA~2.DLL|RevitAddInUtility32.dll"
                view.Modify msiViewModifyUpdate, record    
            ElseIf InStr(record.StringData(1), "RevitAddInUtility64.dll") Then    
                record.StringData(1) = "REVITA~1.DLL|RevitAddInUtility.dll"
                view.Modify msiViewModifyUpdate, record    
            End If    
            Set record = view.Fetch
        Wend
        database.Commit   
    End If
    
Daren Thomas
Sorry, you just broke the install in several ways. For one you changed the name of the assembly without changing the actual contents ( which will break a .NET assembly ) and you also created a component rule violation by changing the keypath with out changing the ComponentID.
Christopher Painter
actually, I changed the name of the assembly *before* adding it to the install and then *changed it back* to the real name afterwards. Could you provide a pointer on "keypath"? I admit to poking around in the dark with a way to short stick here...
Daren Thomas
+1  A: 

Checkout this article for easier ways to accomplish your goal:

RevitAddInUtility for 32 and 64 Bit Systems

Christopher Painter
ah yes. I did read it and kind of brain farted at the implications. Thanks!
Daren Thomas
(But the question itself is not answered yet - I'd love to see an answer to the generic case of replacing a file in an msi!)
Daren Thomas
There is no such generic case. You update the installer source and rebuild the MSI. Do you ever go into a built assembly and update a class with an IL assembler? MSI's are meant to be transformable but this is beyond what a transform should do.
Christopher Painter