C #: Powerpoint non si chiude?
-
06-07-2019 - |
Domanda
Ho uno script che apre Powerpoint dalla mia applicazione ed esporta tutte le diapositive. Successivamente, ho bisogno che l'applicazione venga chiusa.
Ci ho provato senza fortuna. Potresti aiutarmi, per favore?
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);
}
}
}
Soluzione
Vedi la discussione sullo stesso argomento qui: c # ed excel automation - terminando l'istanza in esecuzione
Copre Excel, ma i principi sono esattamente gli stessi.
Riepilogo: devi " rilasciare " gli oggetti Presentations
, Slides
e (multipli) Slide
. A proposito, non mi preoccuperei di impostare le variabili su null. Non è necessario o utile.
Altri suggerimenti
Se qualcun altro sta lottando con questo (non essere in grado di chiudere il PPT dopo aver ripetuto le diapositive), anche dopo aver fatto tutta la raccolta dei rifiuti e liberato risorse, ho passato la parte migliore di oggi a grattarmi la testa con questo. La mia soluzione era, invece di usare un foreach per scorrere le diapositive, ho fatto come segue:
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);
}**
Questo è il mio metodo releaseCOM:
private static void releaseCOM(object o)
{
try
{
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o);
}
catch { }
finally
{
o = null;
}
}
In aggiunta alla risposta di Gary: Per poter rilasciare le raccolte, è necessario assegnarle a variabili temporanee. (Ho usato diapositive e presentazioni come variabili temporanee nell'esempio seguente).
// 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();
}
} } }
Ho un codice che apre powerpoint dalla mia applicazione vb.net, esegue la presentazione, quindi la chiude in seguito. È stato un vero dolore nei glutei trovare tutti gli oggetti com che ho dovuto abbandonare in seguito. Ecco il codice:
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
Spero che questo aiuti qualcuno a saltare lo sforzo extra che ho dovuto fare.