-
Notifications
You must be signed in to change notification settings - Fork 6k
Add comprehensive COM object cleanup documentation and examples for Excel Interop #47088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
ce0f127
7befd6a
69cdbfc
94b85e8
5d03bf1
bcfba59
59e3252
5411805
ce5d34f
c097dc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,6 +96,53 @@ This code demonstrates several of the features in C#: the ability to omit the `r | |
|
||
Press F5 to run the application. Excel starts and displays a table that contains the information from the two accounts in `bankAccounts`. Then a Word document appears that contains a link to the Excel table. | ||
|
||
## Important: COM object cleanup and resource management | ||
|
||
The examples shown above demonstrate basic Office Interop functionality, but they don't include proper cleanup of COM objects. This is a critical issue in production applications because failing to properly release COM objects can result in orphaned Office processes that remain in memory even after your application closes. | ||
|
||
### Why COM object cleanup is necessary | ||
|
||
COM objects in Office Interop require explicit cleanup because: | ||
|
||
- The .NET garbage collector doesn't automatically release COM objects | ||
- Each Excel or Word object you create holds resources that must be manually released | ||
- Without proper cleanup, Office applications remain running in the background | ||
- This applies to all COM objects: Application, Workbooks, Worksheets, Ranges, and more | ||
|
||
### Proper cleanup pattern | ||
|
||
The most reliable way to ensure COM objects are properly released is to factor out the COM object creation and usage into a separate non-inlineable method. This pattern guarantees that object references go out of scope and can be collected: | ||
|
||
:::code language="csharp" source="./snippets/OfficeWalkthrough/ThisAddIn.cs" id="ProperCleanup"::: | ||
|
||
Add the following enhanced version of the `DisplayInExcel` method that includes proper COM object cleanup: | ||
|
||
:::code language="csharp" source="./snippets/OfficeWalkthrough/ThisAddIn.cs" id="DisplayWithCleanup"::: | ||
|
||
This pattern ensures that: | ||
|
||
- COM objects are released even if an exception occurs | ||
- Object references are guaranteed to go out of scope when the core method returns | ||
- Excel processes don't remain orphaned in Task Manager | ||
- Memory is properly freed | ||
- The application behaves reliably in production environments | ||
|
||
For production applications, always implement this cleanup pattern for every COM object you create, including Application, Workbooks, Worksheets, Ranges, and other Office objects. | ||
|
||
|
||
### Common questions about COM object cleanup | ||
|
||
**Why can't garbage collection handle this automatically?** | ||
COM objects use reference counting for memory management, which is different from .NET's garbage collection. The .NET runtime creates a Runtime Callable Wrapper (RCW) around each COM object, but the RCW doesn't automatically release the underlying COM object when it's garbage collected. | ||
|
||
|
||
**Why do you use separate methods with MethodImpl(MethodImplOptions.NoInlining)?** | ||
The .NET JIT compiler can extend object lifetimes until the end of a method, which means local variable assignments to null aren't guaranteed to release references immediately. By factoring out COM object creation and usage into separate non-inlineable methods, you ensure that object references truly go out of scope when the method returns, allowing reliable cleanup. | ||
|
||
**Do I need to call GC.Collect() and GC.WaitForPendingFinalizers()?** | ||
With the separate non-inlineable method pattern, these calls are typically not necessary. The pattern ensures that COM object references go out of scope reliably when the method returns. However, you can optionally add these calls after the separate method call for additional safety in scenarios where you want to force immediate cleanup. | ||
|
||
|
||
**What happens if I don't follow this pattern?** | ||
Without proper cleanup, Office applications remain running in the background even after your application exits. You can verify this by checking Task Manager - you'll see excel.exe or winword.exe processes that weren't properly terminated. These orphaned processes consume memory and can cause issues with future Office automation. | ||
|
||
## Clean up the completed project | ||
|
||
In Visual Studio, select **Clean Solution** on the **Build** menu. Otherwise, the add-in runs every time that you open Excel on your computer. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sample is called "DisplayInExcel". The name suggests that the Excel is expected to say open, displaying the content when the sample finishes executing. Should this be dropped in this sample?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point about the semantic mismatch. I've removed the
excelApp.Quit()
call from the DisplayInExcel method since it's intended to display data to users. Added documentation explaining that for display scenarios, Excel remains open for user interaction, while automation scenarios should include the Quit() call. Fixed in commit 59e3252.