2009-06-11 18 views
9

Oye estoy automatizando PowerPoint y Excel desde una aplicación C# WinForms; lo que hago es leer diapositivas de PowerPoint y guardarlas en Excel y luego salir de ambas aplicaciones. Excel se cierra con éxito pero PowerPoints no se cierra. El problema es que cuando convierto la primera vez, no se cierra, pero cuando la vuelvo a convertir, lo hace.PowerPoint Lanzado a través de C# no sale

Aquí está mi código

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

Respuesta

12

Apagar la aplicación de Microsoft Office puede parecer complicado al principio, pero una vez que estableces el orden correcto de las operaciones, en realidad no es nada difícil.

Liberar su aplicación MS Office se puede hacer con seguridad y eficacia en dos etapas:

(1) En primer lugar liberar todos los objetos de menor importancia a la que no mantiene una referencia dentro de una variable llamada. Para ello, llame al GC.Collect() y luego al GC.WaitForPendingFinalizers(). Tenga en cuenta que si está usando Visual Studio Tools para Office (VSTO), necesita llamar a este par de comandos dos veces para que los objetos COM se liberen correctamente. No está utilizando VSTO, sin embargo, por lo que es suficiente llamarlos una vez.

(2) A continuación, libere explícitamente los objetos que mantiene a través de una variable con nombre mediante una llamada al Marshall.FinalReleaseComObject() en cada variable que tenga.

Recuerde liberar explícitamente todas las variables que tiene para COM componentes. Si pierde una, su aplicación de MS Office se bloqueará. En su código, parece tener tres variables con nombre que contienen una referencia a su aplicación de PowerPoint: ppApp, ppPres y cell.

Tomando todo esto en cuenta, creo que su limpieza debe ser algo como lo siguiente, que hace uso de using System.Runtime.InteropServices ya sea dentro del espacio de nombres o en la parte superior del documento de código:

// using System.Runtime.InteropServices 

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

Marshal.ReleaseComObject(cell); 

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

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

darle un intenta, creo que esto debería funcionar para ti ... (De lo contrario, es posible que tengas que mostrar aún más tu código). Para obtener más información, doy una explicación detallada sobre cómo liberar adecuadamente una aplicación de Excel aquí:

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

Espero que esto ayude, háganos saber cómo va ...

- Mike

+1

Hey Mike gracias, pero este didn Funcionó. Una cosa que quiero decirte es que cuando cierro mi propia aplicación WinForm, también se cierra PowerPoint. – akif

+1

Sí, es normal que se cierre cuando cierras tu WinForm porque cualquier objeto que no se pudo liberar es finalmente lanzamiento d cuando el tiempo de ejecución se derriba. Puede intentar llamar a los finalizadores GC.Collect() y GC.WaitForPending() DOS VECES. Esto no debería importar si no está usando VSTO, pero no puede doler. Tienes que pensar en qué otras variables están en juego aquí ... (Ver el siguiente comentario) –

+2

Debes pensar en qué otras variables están en juego aquí y soltarlas. P. ej .: (1) ¿Hay alguna otra variable estática en alguna parte? (2) ¿Qué hace su llamada InitializeCompany (ref comp, ppPres.Slides [slide])? Si almacena una referencia a una diapositiva de PowerPoint dentro del objeto de su compañía, entonces esta llamada junto con companies.Add (comp) creará una referencia permanente a una referencia de PowerPoint. Estos se deben cortar usando una llamada a Marshal.FinalReleaseComObject() o de lo contrario, PowerPoint se bloqueará. No sé si esto es lo que está sucediendo, pero debe liberar * TODAS * sus referencias de PowerPoint. –

1

Parece que usted está haciendo la instancia de la aplicación Power Point visible, pero si no, es posible que exista un cuadro de diálogo que se presenta que no ve - tal vez una guardar el diálogo de cambios. Si la aplicación se está ejecutando oculta, hágala visible para ver si aparecen dichos cuadros de diálogo, lo que impide que se cierre Power Point.

+0

No, no hay tal cosa :( – akif

0

Después de invocar quit() para su ppApp objeto tratar los siguientes

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

Sin promesas sin embargo, que podría funcionar, o puede no hacer nada en absoluto. El cierre adecuado de Office COM cosas siempre ha sido un poco vudú para mí.

+0

¿No funcionó :( – akif

2

Aquí está un artículo de MSDN que describe el problema y la solución

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

básicamente recomondation es hacer (Nota: dos iteraciones de GC.Collect()

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

Funciona para mí también, pero no puedo entender por qué estas 2 llamadas cambian mi vida. – pix

2

Hie folks.lately he observado que nada funcionó para mí, desde recoger basura hasta dejar y cerrar objetos. e arriba con una alternativa. descubrí el proceso de ejecución una vez que mi trabajo estaba hecho, y luego lo maté a través del código.

Código:

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

Trabajar con esos InteropServices es muy estresante, pero esta solución funcionó, así que gracias. Es gracioso que después de años todavía tenga el mismo problema/dificultad. –

0

este trabajo para mí

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