When you automate a Microsoft Office application from
Microsoft Visual Basic .NET or Microsoft Visual C# .NET, the Office application does not quit when
you call the
Quit method.
When Visual Studio .NET calls a COM object from managed
code, it automatically creates a Runtime Callable Wrapper (RCW). The RCW
marshals calls between the .NET application and the COM object. The RCW keeps a
reference count on the COM object. Therefore, if all references have not been
released on the RCW, the COM object does not quit.
To make sure that the Office application quits, make sure
that your automation code meets the following criteria:
- Declare each object as a new variable. For example, change
the following line of code
oBook = oExcel.Workbooks.Add()
to the following:
dim oBooks as Excel.Workbooks
oBooks = oExcel.Workbooks
oBook = oBooks.Add()
- Use System.Runtime.InteropServices.Marshal.ReleaseComObject when you have finished using an object. This decrements the
reference count of the RCW.
- To release the reference to the variable, set the variable
equal to Nothing or Null.
- Use the Quit method of the Office application object to tell the server to
shut down.
This
behavior is by design.
Steps to reproduce the behavior
- Start Visual Studio .NET.
- On the File menu, click New and then click Project. Under Visual Basic Projects, select Windows Application and click OK. Form1 is created by default.
- Add a reference to the Microsoft Excel Object Library. To do this, follow these steps:
- On the Project menu, click Add Reference.
- On the COM tab, locate the Object Library for Excel, and then click Select.
For Microsoft Excel 2002 : Microsoft Excel 10.0 Object Library
Note If you have not already done so, it is recommended that you
download and install the Microsoft Office XP Primary Interop Assemblies (PIAs).
For additional information about Office XP PIAs, click the following article number to view the article in the Microsoft Knowledge Base:
328912
(http://support.microsoft.com/kb/328912/
)
Microsoft Office XP primary interop assemblies (PIAs) are available for download
For Microsoft Office Excel 2003: Microsoft Excel 11.0 Object Library - Click OK in the Add References dialog box to accept your selections.
- On the View menu, click Toolbox, and then drag a Button control onto Form1.
- Double-click Button1. The code window for the form appears.
- Add the following code to the top of Form1.vb:
Imports Microsoft.Office.Interop
- Replace the following code in the code window
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
End Sub
with the following:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim oApp As New Excel.Application()
Dim oBook As Excel.Workbook = oApp.Workbooks.Add
Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
oSheet = Nothing
oBook.Close(False)
oBook = Nothing
oApp.Quit()
oApp = Nothing
Debug.WriteLine("Sleeping...")
System.Threading.Thread.Sleep(5000)
Debug.WriteLine("End Excel")
End Sub
- Press F5 to run the application.
- Open Windows Task Manager. In Visual Studio, display the
Output window to see the debug messages. Click the command button and note that
an instance of Excel.exe appears in the Processes list.
- The instance of Excel still runs in the task list even
after the application has finished sleeping. Close the dialog box and note that
Excel no longer appears in the Processes list.
- When you implement the steps in the "Resolution" section,
the Office application quits after it releases the last variable. Replace the
function in Step 5 with the following code:
Private Sub NAR(ByVal o As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
Catch
Finally
o = Nothing
End Try
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim oApp As New Excel.Application()
Dim oBooks As Excel.Workbooks = oApp.Workbooks
Dim oBook As Excel.Workbook = oBooks.Add
Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
NAR(oSheet)
oBook.Close(False)
NAR(oBook)
NAR(oBooks)
oApp.Quit()
NAR(oApp)
Debug.WriteLine("Sleeping...")
System.Threading.Thread.Sleep(5000)
Debug.WriteLine("End Excel")
End Sub
If you are using Visual C# .NET, reference the code for the
NAR() function:
private void NAR(object o)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
}
catch {}
finally
{
o = null;
}
}
Troubleshooting
Note that if you follow the steps that are described in the
"Steps to Reproduce the Behavior" section, and the server still does not shut
down, you can use the
GC.Collect() method and the
GC.WaitForPendingFinalizers() method after you release the last object. Because the runtime
performs garbage collection on the RCW, the
GC.Collect() method forces the garbage collector to run and might release any
references that the RCW still has. The
GC.Collect() method tries to reclaim the maximum memory that is available. Note that
this does not guarantee that all memory will be reclaimed.