tags:

views:

64

answers:

2

I've seen a lot of posts returned from a Google search about this, but none of the solutions referenced in them clear this up for me. So, I thought I'd try myself.

After this block of code:

PowerPoint.Application powerPoint = new Microsoft.Office.Interop.PowerPoint.Application();
powerPoint.Visible = Office.MsoTriState.msoTrue;
Microsoft.Office.Interop.PowerPoint.Presentation ppt = null;enter code here

I can issue the ppt.Quit(); command and Powerpoint will close and no Process is left running.

However, if after this code I do this:

ppt = powerPoint.Presentations.Open(localCopyOfPPT,  
                                    Microsoft.Office.Core.MsoTriState.msoCTrue,
                                    Microsoft.Office.Core.MsoTriState.msoTriStateMixed,
                                    Microsoft.Office.Core.MsoTriState.msoTrue);
ppt.Close();
powerPoint.Quit();

Then, the Quit() won't work. Something about opening the presentation, even if I then close it, prevents the Quit() from working, it appears.

Anybody have any thoughts about how I can get the application to quit correctlY?

+3  A: 

The following KB Aritcle might help you get to the bottom of the problem. http://support.microsoft.com/kb/317109

You might need to explicity call System.Runtime.InteropServices.Marshal.ReleaseComObject on your ppt instance.

Chris Taylor
Looks like running ReleaseComObject was the ticket. I had to declare a Presentations object and run the ReleaseComObject method on both it and the ppt object. Once I released both objects, then Application.Quit() worked and no Powerpoint.exe process was left running. This solves a problem I inherited with the code and which has been nagging at me for a long time. Thanks much for the help.
Henry
+1  A: 

powerPoint.Presentations.Open(..)

Note the use of the Presentations object. COM uses manual memory management based on reference counting, every COM interface has an AddRef() and a Release() method. The AddRef call is automatic when you obtain an object. When you're done with it you have to call the Release() method. Using the Presentations object here adds a reference to the Presentations object. Which in turn adds a reference to the internal application object.

That's very incompatible with memory management in the .NET framework. It is automatic, the garbage collector takes care of it. Which it does for COM objects too, the interop wrapper has a finalizer, it decrements the reference count when it sees that no .NET references are left on the COM object.

Perhaps you see where this is going: PowerPoint cannot exit until all object references are released. Which cannot happen until the garbage collector runs and the finalizer thread completed. Your call to the Quit() method does not make the garbage collector run. Only GC.Collect() + GC.WaitForPendingFinalizers can do that.

You can also take the manual approach. It requires Marshal.ReleaseComObject(). Doing this is difficult to get right, note that you don't have a reference to the Presentations object stored anywhere in your code. You'd have to completely rewrite your code to keep track of these references so you can call ReleaseComObject() on them.

I cannot recommend this. If you really really want PowerPoint to quit then the better way is to make sure all your references are null and call GC.Collect() and GC.WFPF. I cannot recommend this either. It will quit, eventually. Don't worry about it.

Hans Passant