9

Hey I'm automating PowerPoint and Excel from a C# WinForms application; what I do is read slides from PowerPoint and save them in Excel and then quit both apps. Excel quits successfully but PowerPoints doesn't quits. The problem is when I convert first time it doesnt quits, but when I convert again it does.

Here is my code

try
{
    PowerPoint.Application ppApp;
    PowerPoint.Presentation ppPres;
    List<Company> companies = new List<Company>();

    ppApp = new PowerPoint.Application();
    ppApp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
    ppApp.WindowState = Microsoft.Office.Interop.PowerPoint.PpWindowState.ppWindowMinimized;

    ppPres = ppApp.Presentations.Open(fileTxtBox.Text,
                                      Microsoft.Office.Core.MsoTriState.msoFalse,
                                      Microsoft.Office.Core.MsoTriState.msoFalse,
                                      Microsoft.Office.Core.MsoTriState.msoTrue);

    int slides = ppPres.Slides.Count;

    for (int slide = 1; slide <= slides; slide++)
    {
        int rows = 1;
        PowerPoint.Cell cell;
        int shape = 1;

        for (; shape < ppPres.Slides[slide].Shapes.Count; shape++)
        {
            if (ppPres.Slides[slide].Shapes[shape].HasTable == Microsoft.Office.Core.MsoTriState.msoTrue)
            {
                cell = ppPres.Slides[slide].Shapes[shape].Table.Cell(1, 1);

                if (cell.Shape.TextFrame.TextRange.Text.Trim().ToLower().Contains("realized"))
                {
                    rows = ppPres.Slides[slide].Shapes[shape].Table.Rows.Count;
                    break;
                }
            }
        }

        Company comp = new Company(rows);
        InitializeCompany(ref comp, ppPres.Slides[slide]);
        companies.Add(comp);
    }

    SaveInExcel(companies);

    ppPres.Close();
    ppPres = null;
    ppApp.Quit();
    ppApp = null;

    return;
}

catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

finally
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
Paul Keister
  • 12,851
  • 5
  • 46
  • 75
akif
  • 12,034
  • 24
  • 73
  • 85

7 Answers7

12

Shutting down your Microsoft Office application can seem tricky to get right at first, but once you establish the correct order of operations, it's actually not very hard at all.

Releasing your MS Office application can be done safely and effectively in two stages:

(1) First release all the minor objects to which you do not hold a reference within a named variable. You do this via a call to GC.Collect() and then GC.WaitForPendingFinalizers() . Note that if you are using Visual Studio Tools for Office (VSTO), then you need to call this pair of commands twice in order to get the COM objects to successfully release. You are not using VSTO, however, so calling them once is sufficient.

(2) Then explicitly release the objects which you hold via a named variable using a call to Marshall.FinalReleaseComObject() on each variable you have.

Remember to explicitly release all variables that you have to COM components. If you miss even one, then your MS Office application will hang. In your code, you seem to have three named variables that hold a reference to your PowerPoint application: ppApp, ppPres, and cell.

Taking this all into account, I think that your cleanup should look something like the following, which makes use of using System.Runtime.InteropServices either within the namespace or at the top of the code document:

// using System.Runtime.InteropServices

// Cleanup:
GC.Collect();
GC.WaitForPendingFinalizers();

Marshal.ReleaseComObject(cell);

ppPres.Close();
Marshal.ReleaseComObject(ppPres);

ppApp.Quit();
Marshal.ReleaseComObject(ppApp);

Give it a try, I think this should work for you... (If not, you might have to show even more of your code.) For further information, I give a detailed explanation on how to properly release an Excel application here:

How to properly clean up Excel interop objects in C#.

Hope this helps, let us know how it goes...

-- Mike

Community
  • 1
  • 1
Mike Rosenblum
  • 12,027
  • 6
  • 48
  • 64
  • 1
    Hey Mike thanks, but this didn't worked. One thing I want to tell you is that when I close my own WinForm app, the PowerPoint closes too. – akif Jun 11 '09 at 16:32
  • 1
    Yes it is normal for it to shut down when you close your WinForm because any objects that you failed to release are finally released when the runtime is torn down. You could try calling GC.Collect() and GC.WaitForPending() finalizers TWICE. This should not matter if you are not using VSTO, but it cannot hurt. You need to think about what other variables are at play here... (See next comment.) – Mike Rosenblum Jun 11 '09 at 17:41
  • 2
    You need to think about what other variables are at play here, and release them. E.g.: (1) Are there any other static variables anywhere? (2) What does your InitializeCompany(ref comp, ppPres.Slides[slide]) call do? If it stores a reference to a PowerPoint slide within your company object, then this call along with companies.Add(comp) will create a permanent reference to a PowerPoint reference. These must be severed using a call to Marshal.FinalReleaseComObject() or else PowerPoint will hang. I don't know if this is what is happening, but you need to release *ALL* your PowerPoint references. – Mike Rosenblum Jun 11 '09 at 17:44
  • 1
    bottom line. seperate your office code from your Winform class. DONT call it directly from the form's class. otherwise the COM objects get stuck in memory till you kill the form. – Anonymous Type May 09 '13 at 06:15
2

Hie folks.lately i have observed that nothing worked out for me from garbage collect to quitting and closing objects. so i came up with an alternative. i found out the running process once my job was done,and then killed it through code.

Code:

 Process[] pros = Process.GetProcesses();
  for (int i = 0; i < pros.Count(); i++)
   {
   if (pros[i].ProcessName.ToLower().Contains("{{NAME_OR_REGEX_FOR_EXPECTED_PPT_NAME}}"))
        {
          pros[i].Kill();
        }
   }
Milind Anantwar
  • 81,290
  • 25
  • 94
  • 125
  • 1
    Work with those InteropServices is very stressful, but this solution worked, so thank you. It's funny that after years it still has same problem/difficult. – Austin Felipe Feb 23 '16 at 13:27
  • Think very carefully before using a solution like this. If I were a user working on 3 different presentations, and I would be very upset at losing my work when the app kills every open PowerPoint application. – Daniel Dec 20 '22 at 15:01
2

Here is a MSDN article that describes the problem and solution

http://msdn.microsoft.com/en-us/library/aa679807%28office.11%29.aspx

basically recomondation is to do(Note : two iterations of GC.Collect()

 GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers(); 
TonyP
  • 5,655
  • 13
  • 60
  • 94
1

It looks like you are making the Power Point application instance visible, but if not, it's possible that there is a dialog being presented that you don't see - perhaps a save changes dialog. If the app is running hidden, make it visible to see if any such dialogs are popping up, preventing Power Point from closing.

Rich.Carpenter
  • 1,056
  • 1
  • 9
  • 21
0

This Work for me

       var app = new PowerPoint.Application();
            PowerPoint.Presentations pres = app.Presentations;
            PowerPoint.Presentation ActivePresentation = pres.Open(fileIn, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
(...)
            ActivePresentation.SaveAs(fileOut, PowerPoint.PpSaveAsFileType.ppSaveAsDefault, MsoTriState.msoTrue);

            ActivePresentation.Close();
            app.Quit();
Paulos02
  • 163
  • 1
  • 4
0

I'm using VSTO in VS2019 for manage Office-365 applications and everything works perfectly using "Application.Quit()" - except Powerpoint!

PP sometimes freezes, sometimes it rises a lot of "ThreadException" for many seconds until quit (I guess it really aborts its Thread). And I had tested all the above code and many other tips found in Google, unsuccessfully.

It's a dirty solution, but it works and close PP immediately after the Presentation had been saved.

But I advise you that my solution is started by the click-event of a button in a custom RIBBON GROUP; otherwise you will have to programmatically "find" the PP window and select it (put focus on it).

GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

SendKeys.Send("%{F4}")

That's all folks...

David BS
  • 1,822
  • 1
  • 19
  • 35
0

After invoking Quit() for your ppApp object try the following

System.Runtime.InteropServices.Marshal.ReleaseComObject(ppApp);

No promises however, it might work, or it might do nothing at all. Properly closing down Office COM stuff has always been a bit like voodoo for me.

Matthew Ruston
  • 4,282
  • 7
  • 38
  • 47