Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to release COM objects in Silverlight 4

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.

like image 354
Joe Avatar asked Apr 09 '11 12:04

Joe


1 Answers

You could implement the IDisposable interface. The best example of this I've seen is at http://csfun.blog49.fc2.com/blog-entry-79.html. The blog entry is in Japanese, but open in Chrome and let Google do the page translation for you if you don't read Japanese.

Also, if you just want the source code example of the COM wrapper directly you can download the sample app it comes in: SilverOffice.

like image 56
Todd Main Avatar answered Oct 05 '22 23:10

Todd Main