Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to Release COM Interop Objects so the Called Program Can Exit

0.00/5 (No votes)
13 Nov 2013 6  
The COM Interop Runtime Callable Wrapper (RCW) is a Black Box that creates references to memory that need to be released before the called program will end.

Introduction

If COM Interop objects are not properly released in your .NET code, the program that your .NET program is communicating with via COM Interop will remain in the Windows operating system task list without a visible window. You can see it in the Details tab of Task Manager.

Background

The common language runtime exposes COM objects through a proxy called the Runtime Callable Wrapper (RCW). To a .NET application, a RCW looks like an ordinary .NET object. It handles calls between a .NET client and a COM object (e.g. The EXCEL.EXE application and objects within EXCEL.EXE) marshaling arguments and return values between the .NET client and the COM object; converting them when necessary.

For each COM object, the .NET runtime creates a single RCW regardless of the number of references to that object. A reference count is incremented each time a new reference is made to the RCW of an instantiated COM object. Calling a "Quit" or "Exit" method followed by a "Dispose" method on a COM object will not free up all of the references. The example code in this tip will ensure that all references are released so that the called COM program will end properly.

Coding Model for COM Interop

  1. Instantiate COM objects just before they are needed. 
  2. Use FinalReleaseComObject(obj) to release objects as soon as they are not needed. 
  3. Call FinalReleaseComObject on the most recently created objects first.
  4. Use the .NET Garbage Collection methods to force garbage collection.

COM Interop Example

My original example is VB .NET code. I used the developerFusion Convert VB .NET to C# tool to convert my VB .NET code to the C# code included in this tip.

VB Example

' Declare a COM object
Dim oApp As Excel.Application 
' Start Excel
oApp = DirectCast(CreateObject("Excel.Application"), Excel.Application)
oApp.Visible = True
Application.DoEvents()
' Open file
oApp.Workbooks.Open(strNewFilename, Excel.XlUpdateLinks.xlUpdateLinksNever)
Application.DoEvents()
' Run the CreateInventoryWorksheets Macro
oApp.Run("CreateInventoryWorksheets")
Application.DoEvents()
' Macro is finished
' Close the file
oApp.ActiveWorkbook.Close(True)
Application.DoEvents()
' Tell Excel to quit
oApp.Quit()
Application.DoEvents()
'
'
' This sample has only one COM object declared. 
' For programs with multiple COM objects declared, repeat the following two
' lines of code for each COM object in reverse order of creation.
' 
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oApp)
oApp = Nothing ' Set each COM Object to Nothing
'
' After all of the COM objects have been released and set to Nothing, do the following:
GC.Collect() ' Start .NET CLR Garbage Collection
GC.WaitForPendingFinalizers() ' Wait for Garbage Collection to finish

C# Example

// Declare a COM object
Excel.Application oApp = default(Excel.Application);
// Start Excel
oApp = (Excel.Application)Interaction.CreateObject("Excel.Application");
oApp.Visible = true;
Application.DoEvents();
// Open file
oApp.Workbooks.Open(strNewFilename, Excel.XlUpdateLinks.xlUpdateLinksNever);
Application.DoEvents();
// Run the CreateInventoryWorksheets Macro
oApp.Run("CreateInventoryWorksheets");
Application.DoEvents();
// Macro is finished
// Close the file
oApp.ActiveWorkbook.Close(true);
Application.DoEvents();
// Tell Excel to quit
oApp.Quit();
Application.DoEvents();
//
//
// This sample has only one COM object declared. 
// For programs with multiple COM objects declared, repeat the following two
// lines of code for each COM object in reverse order of creation.
// 
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oApp);
oApp = null; // Set each COM Object to null
//
// After all of the COM objects have been released and set to null, do the following:
GC.Collect(); // Start .NET CLR Garbage Collection
GC.WaitForPendingFinalizers(); // Wait for Garbage Collection to finish

Points of Interest

Below are links to several articles about COM Interop. Thanks to those authors for their fine articles.

History

  • 29 March 2013 - Initial version
  • 23 October 2013 - Minor edit
  • 12 November 2013 - Removed While Loop of ReleaseComObject and replaced with FinalReleaseComObject

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here