When using COM Interop with Office (usually Excel), I always carefully ensure I call Marshal.ReleaseComObject
on every reference, to avoid the problem where Excel doesn't quit as described in this KB article.
How can I ensure Excel quits when I use Interop from an OOB Silverlight application (with AutomationFactory.CreateObject
)?
Silverlight doesn't have a Marshal.ReleaseComObject
method and even calling GC.Collect
and GC.WaitForPendingFinalizers
doesn't help.
Surely Microsoft hasn't added this feature to Silverlight without a mechanism to release COM references? This seems to me to be a showstopper for automating out-of-process COM servers such as Excel.
A surprising ommission, all the more so as Pete Brown in section 5.5 of his book "Silverlight 4 in Action" goes as far as to say about AutomationFactory.CreateObject
, that:
The primary intent of this feature is to allow automation of other applications, including Microsoft Office.
UPDATE in response to Hans' comments.
I'm not convinced the "silent assassin" problem exists in typical automation of Office apps. A common use might look something like the following, which I've seen used repeatedly in WinForms applications without ever coming across the "poisoned RCW" described in the article linked by Hans:
- Create an Excel.Application instance
- Open or create a workbook
- Write data to the workbook
- Show Excel if all went well, close the workbook and call Application.Quit if not.
- Call Marshal.ReleaseComObject to release all Excel object references.
Failing to call Marshal.ReleaseComObject as recommended by Hans will leave multiple copies of Excel.exe running, as described in the KB article mentioned above - highly undesirable.
UPDATE 2
The sample I'm using to repro this is a sample from the source code for Pete Brown's book Silverlight 4 in action, there's a download link on this page. The sample solution AutomatingExcel is in Ch05.zip / 5.03. To repro:
- Make sure no instances of Excel are running
- Run AutomatingExcel sample
- An Excel workbook is opened
- Close Excel
- Observe with Task Manager that Excel is still running.
Setting all the dynamic variables to null and calling GC.Collect() seems to work as pointed out in AnthonyWJones's answer.
UPDATE 2
Otaku's answer is what I was looking for - by wrapping references in a using statement the COM references are released without the need to call GC.Collect. A bit of experimentation shows that it's more tolerant of failing to dispose every single reference, unlike the standard Marshal.ReleaseComObject
solution described in the KB article referenced above.
It would be interesting to have an authoritative take on exactly what must be disposed to ensure that all Excel references are released.