4

I have a script that opens Powerpoint from my application and exports all slides. After that, I need the application to be closed.

I've tried without any luck. Could you please help?

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Powerpoint = Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using System.Runtime.InteropServices;

namespace PresentrBuilder
{


class PowerpointConverter
{

    public static void Convert(String file, String safeFile)
    {
        Powerpoint.Application PP;
        Powerpoint.Presentation Presentation;

        PP = new Powerpoint.ApplicationClass();
        PP.Visible = MsoTriState.msoTrue;
        PP.WindowState = Microsoft.Office.Interop.PowerPoint.PpWindowState.ppWindowMinimized;
        Presentation = PP.Presentations.Open(file, MsoTriState.msoFalse, MsoTriState.msoTrue, MsoTriState.msoTrue);

            // Voor elke slide, exporteren
            String exportSlidesPath = Path.Combine(Properties.Settings.Default.CacheDir, @"presentatienaam1\slides");

            // Kijk of de directory bestaat
            if (!Directory.Exists(exportSlidesPath))
            {
                Directory.CreateDirectory(exportSlidesPath);
            }

                // Kijk of er al bestanden in de directory staan
                // Zo ja: verwijderen
                String[] files = Directory.GetFiles(exportSlidesPath, "*.png");
                if (files.Length > 0)
                {
                    foreach (string fileName in files)
                    {
                        File.Delete(Path.Combine(exportSlidesPath, fileName));
                    }
                }

            // Elke slide exporteren
            foreach (Slide slide in Presentation.Slides)
            {
                slide.Export(Path.Combine(exportSlidesPath, "slide_" + slide.SlideIndex + ".png"), "PNG", 1024, 768);
                Marshal.ReleaseComObject(slide);
            }


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

        Marshal.ReleaseComObject(PP.Presentations);
        Marshal.ReleaseComObject(Presentation.Slides);

        Presentation.Close();
        Marshal.FinalReleaseComObject(Presentation);

        PP.Quit();
        Marshal.FinalReleaseComObject(PP);

    }

}
}
MysticEarth
  • 2,646
  • 4
  • 33
  • 53
  • You've edited your code above, but it's still not right. You call PP.Presentations (and Presentation.Slides) twice, once to use them and then once to release the reference. However it doesn't work like that - each time you invoke them, you create another reference. You need to invoke them once, and store the reference in a variable that you can then release (as per Andre's answer). – Gary McGill Oct 26 '09 at 15:46
  • 1
    possible duplicate of [PowerPoint Launched via C# does not Quit](http://stackoverflow.com/questions/981547/powerpoint-launched-via-c-sharp-does-not-quit) – Paul Keister Aug 07 '12 at 18:17
  • Try calling Collect and Wait from another method, after this completing this method call – nawfal Feb 05 '14 at 14:58

4 Answers4

3

If anyone else is struggling with this (not being able to close the PPT after iterating through the slides), even after doing all the garbage collection and releasing resources, I spent the better part of today scratching my head with this one. My solution was, instead of using a foreach to iterate through the slides, i did as follows:

        Microsoft.Office.Interop.PowerPoint.Application powerpoint;
        Microsoft.Office.Interop.PowerPoint.Presentation presentation;
        Microsoft.Office.Interop.PowerPoint.Presentations presentations;

        powerpoint = new Microsoft.Office.Interop.PowerPoint.ApplicationClass();
        powerpoint.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
        presentations = powerpoint.Presentations;

        presentation = presentations.Open(localPath, MsoTriState.msoFalse, MsoTriState.msoTrue, MsoTriState.msoTrue);


        //String presentationTitle = objPres.Name;
        Microsoft.Office.Interop.PowerPoint.Slides slides = presentation.Slides;
        **for (int i = 1; i <= slides.Count; i++)
        {
            Microsoft.Office.Interop.PowerPoint.Slide slide = slides[i];
            String slideName = slide.Name;
            releaseCOM(slide);
        }**

This is my releaseCOM method:

    private static void releaseCOM(object o)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o);
        }
        catch { }
        finally
        {
            o = null;
        }
    }
stompkins
  • 31
  • 3
2

See the discussion on the same topic here: c# and excel automation - ending the running instance

It covers Excel, but the principles are exactly the same.

Summary: you need to "release" the Presentations, Slides and (multiple) Slide objects. BTW, I wouldn't bother setting the variables to null. That's not necessary or helpful.

Community
  • 1
  • 1
Gary McGill
  • 26,400
  • 25
  • 118
  • 202
  • ell, I've tried to release all of the objects that have a reference to Powerpoint, nothing seems to help... I'm releasing all the Slide objects with Marshal.ReleaseComObject(slide);. – MysticEarth Oct 26 '09 at 14:07
  • 1
    Are you releasing the PP.Presentations and Presentation.Slides Object as well? People often forget about the collections the use. – Andre Kraemer Oct 26 '09 at 14:20
  • could you please edit your question and post your updated code? – Andre Kraemer Oct 26 '09 at 14:29
0

As an addition to Gary's answer: In Order to release the collections, you have to assign them to temporary variables. (I used slides and presentations as temp variables in the example below).

  // removed using statements...

    namespace PresentrBuilder
    {


      class PowerpointConverter
      {

      public static void Convert(String file, String safeFile)
      {
        Powerpoint.Application PP;
        Powerpoint.Presentation Presentation;

        PP = new Powerpoint.ApplicationClass();
        // ...
        var presentations = PP.Presentations;
           try
            {
        Presentation = presentations.Open(file, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);

            // Voor elke slide, exporteren
            // ...

            // Elke slide exporteren
            var slides = Presentation.Slides;

            foreach (Slide slide in slides)
            {
                slide.Export(Path.Combine(exportSlidesPath, "slide_" + slide.SlideIndex + ".png"), "PNG", 1024, 768);
                Marshal.ReleaseComObject(slide);
            }
  Marshal.ReleaseComObject(presentations);
        Marshal.ReleaseComObject(slides);

        Presentation.Close();
        Marshal.FinalReleaseComObject(Presentation);
         }
        catch (System.Exception err){}
        finally{

       // GC.WaitForPendingFinalizers();    

        PP.Quit();
        Marshal.FinalReleaseComObject(PP);
        GC.Collect();
      } 
 } } }
Saroop Trivedi
  • 2,245
  • 6
  • 31
  • 49
Andre Kraemer
  • 2,633
  • 1
  • 17
  • 28
0

I have code that opens powerpoint from my vb.net application, runs the slide show, then closes it afterwards. It was a real pain in the buttocks to find all the com objects I had to drop afterwards. Here's the code:

Imports MSWord = Microsoft.Office.Interop.Word
Imports MSPowerPt = Microsoft.Office.Interop.PowerPoint
Imports MSExcel = Microsoft.Office.Interop.Excel

Dim MSPowerPtApp As MSPowerPt.Application
Dim MSPowerPtPresentation As MSPowerPt.Presentation
Dim MSPowerPtPresentations As MSPowerPt.Presentations
Dim MSPowerPtSettings As MSPowerPt.SlideShowSettings
Dim MSPowerPtSlideShowWindow As MSPowerPt.SlideShowWindow
Dim MSPowerPtSlideShowWindows As MSPowerPt.SlideShowWindows

Function Display_PowerPoint_Show(ByVal filename As String)
  Dim MSPowerPtSlides As MSPowerPt.Slides
  Display_PowerPoint_Show = True
  Try
    If (Not FileExists(filename)) Then
      Display_PowerPoint_Show = False
      MsgBox("Display_PowerPoint_Show: Text file: " & filename & " not found", MsgBoxStyle.Information, "File Not Found")
      GoTo Exit_Display_PowerPoint_Show
    End If

    MSPowerPtApp = New MSPowerPt.Application
    MSPowerPtApp.Visible = True
    MSPowerPtApp.WindowState = MSPowerPt.PpWindowState.ppWindowMinimized

    'Create a new presentation that is based on the specified template.
    MSPowerPtPresentations = MSPowerPtApp.Presentations
    MSPowerPtPresentation = MSPowerPtPresentations.Open(lbFiles.SelectedValue, True)
    MSPowerPtSlides = MSPowerPtPresentation.Slides

    If (MSPowerPtSlides.Count = 0) Then
      MsgBox("This Powerpoint file has no slides", MsgBoxStyle.Information, "No Slides in File")
      GoTo ClosePowerPointFile
    End If

    MSPowerPtSettings = MSPowerPtPresentation.SlideShowSettings
    MSPowerPtSettings.StartingSlide = 1
    MSPowerPtSettings.EndingSlide = 1

    ''Run the slide show and wait for the slide show to end.
    MSPowerPtSlideShowWindow = MSPowerPtSettings.Run()
    MSPowerPtSlideShowWindows = MSPowerPtApp.SlideShowWindows

    Do While MSPowerPtSlideShowWindows.Count >= 1
      System.Windows.Forms.Application.DoEvents()
    Loop

    'Close the presentation without saving changes and then quit MSPowerPt.
    MSPowerPtPresentation.Saved = True
    MSPowerPtPresentation.Close()

    RemoveComObjRef(MSPowerPtSlideShowWindow)
    RemoveComObjRef(MSPowerPtSlideShowWindows)
    RemoveComObjRef(MSPowerPtSettings)

ClosePowerPointFile:
    RemoveComObjRef(MSPowerPtSlides)
    RemoveComObjRef(MSPowerPtPresentation)
    RemoveComObjRef(MSPowerPtPresentations)

    'Quit MSPowerPt.
    MSPowerPtApp.Quit()
    RemoveComObjRef(MSPowerPtApp)
    GC.Collect()

  Catch ex As Exception
    Display_PowerPoint_Show = False
    MsgBox("Display_PowerPoint_Show - File: " & filename & ", Error: " & ex.Message & " reading file", _
           MsgBoxStyle.Information, "Error Reading File")
  End Try

Exit_Display_PowerPoint_Show:
End Function

'RemoveComObjRef function to remove reference.
Private Sub RemoveComObjRef(ByVal ComObject As Object)
  Try
    System.Runtime.InteropServices.Marshal.ReleaseComObject(ComObject)
  Catch
  Finally
    ComObject = Nothing
  End Try
End Sub

I hope this helps someone to skip the extra effort I had to put in.

LarsTech
  • 80,625
  • 14
  • 153
  • 225