Build 64-bit MSI file on Cruise Control

There is a known bug when trying to build 64-bit MSI files.  That is, the wrong InstallUtilLib.dll is embedded in the MSI.  A workaround to that problem is to use Orca to manually manipulate the MSI file in embed the correct version - the workaround is documented here.  However, what if you want to automate this process on your build server?  Orca is a windows appication requiring user input.

To automate this from the command line, you can leverage a few lines of VBScript code that essentially duplicates the Orca functionality.  Specifically, what we are trying to do is embed the 64-bit version of InstallUtilLib.dll into the MSI so that the BadImageFormatException does not rear its ugly head.  The key line of the VBScript is the SetStream method of the Record object.  The complete VBScript solution is shown below and can simply be invoked from CCNet using a standard command line task such as the Exec MSBuild task with the appropriate command line arguments.

    Option Explicit  
    On Error Resume Next

    Const msiViewModifyInsert         = 1  
    Const msiViewModifyUpdate         = 2  
    Const msiViewModifyAssign         = 3  
    Const msiViewModifyReplace        = 4  
    Const msiViewModifyDelete         = 6

    If (WScript.Arguments.Count = 0) Then  
       Msgbox("No command line argument specified for MSI location. Please try again.")  
       Wscript.Quit 1  
    Else  
     AdjustInstallUtil()  
    End If

     

    public sub AdjustInstallUtil()  
     On Error Resume Next  
       
     dim msiInstance : msiInstance = WScript.Arguments.Item(0)  
     dim installer : Set installer = CreateObject("WindowsInstaller.Installer")   
     dim installerDb : Set installerDb = installer.OpenDatabase(cstr(msiInstance), 1)  
     dim sqlCommand : sqlCommand = "SELECT * FROM Binary WHERE `Name`='InstallUtil'"  
     dim view : Set view = installerDb.OpenView(sqlCommand)

     view.Execute()  
     dim record : Set record = view.Fetch()

     If Not record Is Nothing Then  
      const dataCol = 2  
      record.SetStream dataCol, "C:Program FilesCruiseControl.NET64BitMSIInstallUtilLib.dll"  
      view.Modify msiViewModifyUpdate, record  
      installerDb.Commit  
     End IF  
       
     'clean up  
     Set installerDb = Nothing  
     Set view = Nothing  
     Set installer = Nothing  
       
     'Error Handling  
     If Err.number > 0 Then  
       Msgbox("Error while adjusting x64 InstallUtilLib: " & Err.Description & ": " & Err.Source & ": " & Err.number)  
     End If   
    end sub  
Tweet Post Share Update Email RSS