Sign in with Microsoft
Sign in or create an account.
Hello,
Select a different account.
You have multiple accounts
Choose the account you want to sign in with.

See the other products that this article applies to.

Symptoms

When you automate a Microsoft Office application from Microsoft Visual Basic .NET or Microsoft Visual C# .NET, the Office application does not exit when you call the Quit method.

Cause

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.

Resolution

To make sure that the Office application exits, determine whether 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()
    

    Change this to the following:

    dim oBooks as Excel.Workbooks
    oBooks = oExcel.Workbooks
    oBook = oBooks.Add()
    
  • Use System.Runtime.InteropServices.Marshal.ReleaseComObject in a loop until it returns 0 when you have finished using an object. The System.Runtime.InteropServices.Marshal.ReleaseComObject decrements the reference count of the RCW, and the loop makes sure that the underlying COM component is released regardless of how many times it has re-entered the CLR.

  • 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.

Status

This behavior is by design.

More Information

Steps to reproduce the behavior

  1. Start Visual Studio .NET.

  2. On the File menu, click New, and then click Project. Under Visual Basic Projects, select Windows Application, and then click OK.

    Note Form1 is created by default.

  3. Add a reference to the Microsoft Excel Object Library. To do this, follow these steps:

    1. On the Project menu, click Add Reference.

    2. 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 this, we recommend that you download and install the Microsoft Office XP Primary Interop Assemblies (PIAs).

      For more information about Office XP PIAs, go to the following Microsoft Knowledge Base article:

      328912 Microsoft Office XP primary interop assemblies (PIAs) are available for download
        For Microsoft Office Excel 2003: Microsoft Excel 11.0 Object Library

    3. Click OK in the Add References dialog box to accept your selections.

  4. On the View menu, click Toolbox, and then drag a Button control onto Form1.

  5. Double-click Button1.

    Note The code window for the form appears.

  6. Add the following code to the top of Form1.vb:

    Imports Microsoft.Office.Interop
    
  7. 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
    

    Substitute the following code:

    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
    
  8. Press F5 to run the application.

  9. Open Windows Task Manager. In Visual Studio, display the Output window to see the debug messages. Click the command button. Notice that an instance of Excel.exe appears in the Processes list.

  10. The instance of Excel still runs in the task list even after the application has finished sleeping. Close the dialog box and notice that Excel no longer appears in the Processes list.

  11. When you do the steps in the "Resolution" section, the Office application exits after it releases the last variable. Replace the function in Step 5 by using the following code:

      Private Sub NAR(ByVal o As Object)
        Try
          While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
          End While
        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 
    {
        while (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) ;
    }
    catch {}
    finally 
    {
        o = null;
    }
}

Note Starting in .NET Framework 2.0, you can use System.Runtime.InteropServices.Marshal.FinalReleaseComObject instead of the while loop calling System.Runtime.InteropServices.Marshal.ReleaseComObject to achieve the same result.
 

Troubleshooting

Note 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. Notice that this does not guarantee that all memory will be reclaimed.

 

Applies to

This article also applies to:

  • Microsoft Visual Basic .NET (all editions)

  • Microsoft Visual C# .NET (all editions)

  • Microsoft Office 2016 (all editions)

  • Microsoft Office 2013 (all editions)

Need more help?

Want more options?

Explore subscription benefits, browse training courses, learn how to secure your device, and more.

Communities help you ask and answer questions, give feedback, and hear from experts with rich knowledge.

Was this information helpful?

What affected your experience?
By pressing submit, your feedback will be used to improve Microsoft products and services. Your IT admin will be able to collect this data. Privacy Statement.

Thank you for your feedback!

×