2009-06-11 6 views
9

Hey Ich automatisiere PowerPoint und Excel aus einer C# WinForms-Anwendung; Ich lese Folien aus PowerPoint und speichere sie in Excel und dann beide Apps. Excel wird erfolgreich beendet, PowerPoints wird jedoch nicht beendet. Das Problem ist, wenn ich das erste Mal konvertiere, wird es nicht beendet, aber wenn ich es wieder konvertiere, tut es das.PowerPoint gestartet über C# beendet nicht

Hier ist mein 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(); 
} 

Antwort

12

Das Herunterfahren Ihrer Microsoft Office-Anwendung kann schwierig erscheinen, um zunächst richtig zu arbeiten, aber sobald Sie die richtige Reihenfolge der Operationen eingerichtet haben, ist es überhaupt nicht sehr schwer.

Releasing Ihre MS Office-Anwendung sicher und effektiv in zwei Stufen durchgeführt werden kann:

(1) Lösen Sie alle kleineren Objekte, auf die Sie keine Referenz im benannten Variablen halten. Sie tun dies über einen Anruf an GC.Collect() und dann GC.WaitForPendingFinalizers(). Wenn Sie Visual Studio-Tools für Office (VSTO) verwenden, müssen Sie dieses Befehlspaar zweimal aufrufen, damit die COM-Objekte erfolgreich freigegeben werden. Sie verwenden VSTO jedoch nicht, daher ist ein einmaliger Aufruf ausreichend.

(2) Geben Sie die Objekte, die Sie über eine benannte Variable halten, explizit frei, indem Sie für jede Variable Marshall.FinalReleaseComObject() aufrufen.

Denken Sie daran, alle Variablen explizit freizugeben, die Sie COM-Komponenten haben müssen. Wenn Sie nur eine verpassen, wird Ihre MS Office-Anwendung hängen bleiben. In Ihrem Code scheinen Sie drei benannte Variablen zu haben, die einen Verweis auf Ihre PowerPoint-Anwendung enthalten: ppApp, ppPres und cell.

dies Unter Berücksichtigung all berücksichtigt, denke ich, dass Ihre Bereinigung etwas wie folgt aussehen sollte, die entweder im Namensraum oder am oberen Rand des Code Dokument Verwendung von using System.Runtime.InteropServices macht:

// using System.Runtime.InteropServices 

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

Marshal.ReleaseComObject(cell); 

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

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

Geben Sie ihm einen versuchen Sie, ich denke, das sollte für Sie arbeiten ... (Wenn nicht, müssen Sie möglicherweise noch mehr von Ihrem Code zeigen.) Für weitere Informationen gebe ich eine detaillierte Erklärung, wie eine Excel-Anwendung hier richtig freigeben:

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

Hoffe das hilft, lassen Sie uns wissen, wie es geht ...

- Mike

+1

Hey Mike Dank, aber dieses didn 't hat funktioniert. Eine Sache, die ich dir sagen will, ist, dass, wenn ich meine eigene WinForm-Anwendung schließe, auch die PowerPoint-Datei schließt. – akif

+1

Ja, es ist normal, dass es heruntergefahren wird, wenn Sie WinForm schließen, weil alle Objekte, die Sie nicht freigeben konnten endlich freilassen d wenn die Laufzeit heruntergefahren wird. Sie könnten versuchen, GC.Collect() und GC.WaitForPending() Finalizer TWICE aufzurufen. Dies ist nicht wichtig, wenn Sie nicht VSTO verwenden, aber es kann nicht weh tun. Sie müssen darüber nachdenken, welche anderen Variablen hier spielen ... (Siehe nächsten Kommentar.) –

+2

Sie müssen darüber nachdenken, welche anderen Variablen hier spielen, und sie freigeben. Zum Beispiel: (1) Gibt es irgendwo andere statische Variablen? (2) Was bewirkt Ihr Aufruf InitializeCompany (ref comp, ppPres.Slides [slide])? Wenn Sie einen Verweis auf eine PowerPoint-Folie innerhalb Ihres Unternehmensobjekts speichern, wird dieser Aufruf zusammen mit companies.Add (comp) einen permanenten Verweis auf eine PowerPoint-Referenz erstellen. Diese müssen durch einen Aufruf von Marshal.FinalReleaseComObject() getrennt werden, da sonst PowerPoint hängen bleibt. Ich weiß nicht, ob das so ist, aber Sie müssen * ALLE * Ihre PowerPoint-Referenzen veröffentlichen. –

1

Es sieht aus wie Sie die Power-Point-Anwendungsinstanz sichtbar zu machen sind, aber wenn nicht, dann ist es möglich, dass es ein Dialogfeld angezeigt wird, ist, dass Sie nicht sehen - vielleicht ein Änderungsdialog speichern. Wenn die App verborgen ausgeführt wird, sollten Sie sie sichtbar machen, um zu sehen, ob solche Dialoge auftauchen und Power Point daran hindert, sich zu schließen.

+0

Nein, es ist nicht so etwas :( – akif

0

Nach dem Aufruf Quit() für Ihre ppApp Objekt versuchen Sie die folgenden

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

Keine aber verspricht, könnte es funktionieren, oder es könnte überhaupt nichts tun. Richtiges Schließen von Office-COM-Sachen war für mich immer ein bisschen wie Voodoo.

+0

nicht gearbeitet Hat :( – akif

2

Hier ist ein MSDN-Artikel, der das Problem und Lösung

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

grundsätzlich recomondation zu tun ist (Anmerkung beschreibt: zwei Wiederholungen von GC.Collect()

GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
+0

Es funktioniert auch für mich, aber ich kann nicht herausfinden, warum diese 2 Anrufe mein Leben verändern. – pix

2

Hie Leute.leicht habe ich beobachtet, dass nichts für mich von Müll sammeln, um Objekte zu beenden und zu schließen, also ich cam mit einer Alternative. Ich habe den laufenden Prozess gefunden, nachdem meine Arbeit erledigt wurde, und dann den Code durch Code gelöscht.

Code:

Process[] pros = Process.GetProcesses(); 
    for (int i = 0; i < pros.Count(); i++) 
    { 
    if (pros[i].ProcessName.ToLower().Contains("powerpnt")) 
     { 
      pros[i].Kill(); 
     } 
    } 
+1

Arbeiten mit diesen InteropServices ist sehr stressig, aber diese Lösung hat funktioniert, also danke. Es ist lustig, dass es nach Jahren immer noch das gleiche Problem/schwierig hat. –

0

diese Arbeit für mich

 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(); 
Verwandte Themen