65.9K
CodeProject is changing. Read more.
Home

Release Excel Object

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.29/5 (24 votes)

Jan 17, 2005

2 min read

viewsIcon

155894

How to kill Excel object.

Introduction

Nearly every developer has encountered one day what I have encountered when dealing with a COM object and the pain in releasing it from memory.

In the following example, I will describe my experience about how I solved an issue with the Excel object, and the way I followed to kill those hanging objects, where I tried many known methods and none worked.

The key of my successful experience is, I got to know every object that is created explicitly or implicitly when calling one of the methods for some Excel object, and especially the sequence while creating/killing those created objects. There's nothing new in my example except the way I'm handling the life cycle of the object. This article is completely based on my own personal views and experiences.

Start by creating an Excel file that consists of five sheets, add some rows with some values in some cells to each sheet. (Make sure that the second and the sixth cells have values.) Make the sixth cell as hyperlink by right clicking and assigning some address to it, and save the file under the c:\myExcel.xls folder.

Create a new ASP.NET web project in Visual Studio .NET. Look under the Project dropdown menu, select Add Reference, then click on the COM tab. Select the Microsoft Excel Object Library, add it to your references, and click on OK to close the dialog.

Open the code behind the file of WebForm1 and enter the following code:

Sub Page_Load createAndKillExcelObject()
End Sub
 
Private Sub createAndKillExcelObject()
 
    'I used late binding to resolve the issue from 
    'the difference in version 
    ' between my machine and the server
    'This method is SLOW, but it ensure the 
    'appropriate release of all Excel's 
    ' objects the excel file in subject here, 
    'consist of 1 book and many sheets.
    'each sheet consist of different number of rows
    'in this example:
    'I want to get to the second cell (cell(2) ) 
    'in each row in each sheet to get 
    ' to its Text property
    ' +
    ' to the sixth cell ( cell(6) ) in each row 
    'in each sheet to extract the 
    ' Hyperlink value.
    
    'Based on the same logic followed here, 
    '(creating and killing objects in the 
    ' SAME SEQUENCE) you can extend this logic to fit your need.
    
    Dim someExcelFile As String = "c:\myExcel.xls"
    
    'note the sequence in creating Excel objects.
    'the followed sequence (creating and killing) 
    'is the key to release Excel 
    'object at the end.
     
    Dim xl As Object
    xl = CreateObject("Excel.Application")
     
    'creating and pointing 'myWorkbooks' variable 
    'to the Excel's workbook object.
    'Excel's workbooks has a 'Close()' property, 
    'that I will call it later for 
    'myWorkbooks before killing it.
    'NOTE: if you have more than 1 workbook, you need to kill them all 
    '       individually before the workbooks object to be released. 
    Dim myWorkbooks As Object = xl.Workbooks
    xl.Visible = False 
    myWorkbooks.Open(someExcelFile)  
    
    'we need to access each sheet individually, 
    'therefore, I create 'mySheets' 
    'object that contains the individuals sheets, 
    'which for, we'll create an 
    'individual variables, that point to each sheet 
    'contained in 'mySheets' object.
    
    'creating and pointing 'mySheets' variable to 
    'the Excel's worksheets object.
    ' 'mySheets' object contains more 5 sheets.
    'in order to kill 'mySheets' object, we need 
    'to kill every sheet individually, 
    ' before 'mySheets' to be released
    Dim mySheets As Object
    mySheets = xl.Workbooks(1).Worksheets
     
    'NOTE:
    'calling the 'Count' property of Wroksheets 
    'will create automatically
    'the individual sheets contained in mySheets object, 
    'which will not be visible
    'to you, but they will exist in memory. 
    'And without killing those sheets
    'individually, we would not be able to kill mySheets object.
    'By assigning those individual sheets to 
    'a variables, we can keep track of them
    'and kill them when needed.
    
    'mySheetArray contains those individuals sheets in mySheets object.
    
    Dim mySheetCount As Int16 = mySheets.count
    
    'mySheetArray that contains the individuals sheets in mySheets object
    Dim mySheetArray(mySheetCount) As Object
    Dim i, j, k As Int16
    
    For i = 1 To mySheetCount
        mySheetArray(i) = mySheets(i)
        
        'create a variable that point to the 
        'range object in each sheet contained in 
        'mySheets object.
        'We'll release this range later as part 
        'of our process to release Excel object
        Dim myRanges As Object = mySheets(i).UsedRange
         
        'create a variable that point to the 
        ''Columns' object in myRanges object.
        'We'll release this columns object later 
        'as part of our process to release 
        'Excel object
        Dim myColumns As Object = myRanges.Columns
        Dim myColumnsCount As Int16 = myColumns.Count
        
        'create a variable that point to 
        ''myRows' object in myRanges object.
        'We'll release this Rows object later 
        'as part of our process to release 
        'Excel object
        Dim myRows As Object = myRanges.Rows
        Dim myRowsCount As Int16 = myRows.Count
        
        'myRowArray will contains all rows 
        'contained in 'myRows' object
        Dim myRowArray(myRowsCount) As Object
        
        For j = 1 To myRowsCount
        
            'assign each row in 'myRows' object to a variable
            myRowArray(j) = myRows(j)
            
            'extract the sixth cell's value in this row
            Dim myColumns_6 As Object = myRowArray(j).Cells(6)
            
            'myHyperlink variable point to the Hyperlink object
            'specific to each column contained in myColumns object
            Dim myHyperlink As Object = myColumns_6.Hyperlinks
            
            If myHyperlink.Count > 0 Then 
            
                'myHyperlink_1 point to the first 
                'Hyperlink object contained
                'in myColumns_6 object, contained in myColumns object
                Dim myHyperlink_1 As Object = myColumns_6.Hyperlinks(1)
                
                'calling the 'Address' property of 
                'myHyperlink1 return a String
                '(no hidden object in memory is created 
                'when calling this property)
                Dim adress As String = myHyperlink_1.Address
                
                'we need to access the second cell in this sheet,
                'so, let's start by creating the 'myCells' 
                'object, that contains all cells.
                Dim myCells As Object = myRowArray(j).Cells
                
                'myCells_2 point to cell with the index 
                '2 contained in myCells object
                Dim myCells_2 As Object = myCells(2)
                
                Dim cellText As String
                cellText = myCells_2.Text
                
                 'start releasing all object by the 
                'same sequence that were created.
                '(last to first)
                
                ReleaseComObject(myCells_2)
                ReleaseComObject(myCells)
                ReleaseComObject(myHyperlink_1)
            End If
            ReleaseComObject(myHyperlink)
            ReleaseComObject(myColumns_6)
            ReleaseComObject(myRowArray(j))
        Next
        myRowArray = Nothing
        ReleaseComObject(myColumns)
        ReleaseComObject(myRows)
        ReleaseComObject(myRanges)
        ReleaseComObject(mySheetArray(i))
    Next
    mySheetArray = Nothing
    ReleaseComObject(mySheets)
    xl.Workbooks(1).Close(False)
    ReleaseComObject(myWorkbooks)
    xl.Quit() ReleaseComObject(xl)
End Sub
 
Private Sub ReleaseComObject(ByRef Reference As Object)
    Try        
        Do Until _
         System.Runtime.InteropServices.Marshal.ReleaseComObject(Reference)<=0
        Loop
    Catch
    Finally
        Reference = Nothing
    End Try
End Sub

Open the "Task Manager" window, run this code and watch the Excel process created and released. Note: Make sure that ASP_NET process has the right permissions to create the Excel object before you run this code.

To give ASP.NET the permissions it needs to use Excel, you might need to add the line <identity impersonate="true"/> to your web.config file or configure your app to run under an appropriate user account.

All comments are welcome.