WinWord.exe no se cerrará después de llamar a Word.Documents.Add – Word .NET Interop

Me encuentro con el escenario clásico donde, al crear objetos Word COM en .NET (a través del ensamblado Microsoft.Office.Interop.Word), el proceso WinWord no se cerrará aunque esté cerrando y soltando correctamente los objetos .

Lo he reducido al uso del método Word.Documents.Add (). Puedo trabajar con Word de otras formas sin problemas (abrir documentos, modificar contenidos, etc.) y WinWord.exe se cierra cuando se lo digo. Una vez que uso el método Add () (y solo cuando agrego una plantilla ), el proceso se deja en ejecución.

Aquí hay un ejemplo simple que reproduce el problema:

Dim word As New Word.Application() word.Visible = False Dim documents As Word.Documents = word.Documents Dim doc As Word.Document = documents.Add(Template:=CObj(templatePath), NewTemplate:=False, DocumentType:=Word.WdNewDocumentType.wdNewBlankDocument, Visible:=False) '' dispose objects doc.Close() While (Marshal.ReleaseComObject(doc)  0) End While doc = Nothing While (Marshal.ReleaseComObject(documents)  0) End While documents = Nothing word.Quit() While (Marshal.ReleaseComObject(word)  0) End While word = Nothing GC.Collect() 

Como puede ver, estoy creando y eliminando los objetos correctamente, incluso dando el paso adicional para repetir Marsha.ReleaseComObject hasta que devuelva el código correcto. Trabajar con los objetos de Word está bien en otros aspectos, es solo ese molesto Documents.Add que me está causando dolor. ¿Hay algún otro objeto que se cree en este proceso que necesite referenciar y eliminar? ¿Hay algún otro paso de eliminación que deba seguir? ¿Algo más? Su ayuda es muy apreciada 🙂

Update: Intenté GC.Collect al final del paso de eliminación pero todavía no tuve suerte.

Update 2: reduje el problema al uso de plantillas personalizadas. Cuando invoco Documents.Add (…) especifico una plantilla personalizada para el nuevo documento. Si no hago esto y en su lugar invoco Agregar () sin parámetros, entonces el problema no ocurre.

(Todos mis consejos están adaptados de esta respuesta sobre la interoperabilidad de Excel).

Aquí hay algunas cosas importantes:

1) Nunca use 2 puntos en la misma línea. Considere también un indexador como un punto

Bueno

 Word.Documents d = wordApp.Documents; Word.Document aDoc = d.Open(/*...*/); 

MALO

 Word.Document aDoc = wordApp.Documents.Open(/*...*/); 

2) Libere todos sus punteros.

3) No, realmente, retrocede y suelta todos tus punteros, te perdiste uno en alguna parte (o al menos siempre lo hago).

Aquí hay un ejemplo completo de lo que FINALMENTE funcionó para mí en un proyecto después de mucho llanto y rechinar de dientes:

 object m = Missing.Value; // this must be an object, not a string. if you forget though, // intellisense will remind you object oFilename = @"C:\my sheet.doc"; object readOnly = false; object isVisible = false; Word.Application wordApp = new Word.ApplicationClass(); wordApp.Visible = false; // remember: don't use 2 dots on 1 line Word.Documents d = wordApp.Documents; Word.Document aDoc = d.Open(ref oFilename, ref m, ref readOnly, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref isVisible, ref m, ref m, ref m, ref m); aDoc.Activate(); object findText = "my old value"; object replaceText = "new and improved value"; object oTrue = true; object oFalse = false; object replace = 2; object wrap = 1; Word.Selection s = wordApp.Selection; Word.Find f = s.Find; f.Execute(ref findText, ref oTrue, ref oTrue, ref oFalse, ref oFalse, ref oFalse, ref oTrue, ref wrap, ref oFalse, ref replaceText, ref replace, ref oFalse, ref oFalse, ref oFalse, ref oFalse); aDoc.SaveAs(ref oFilename, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m); object doNotSaveChanges = Word.WdSaveOptions.wdDoNotSaveChanges; // casting here because intellisense complained of ambiguity (aDoc as Word._Document).Close(ref doNotSaveChanges, ref m, ref m); // release each in the reverse of the order in which it was first used // ReleaseComObject might also work as well. I haven't tested yet Marshal.FinalReleaseComObject(f); Marshal.FinalReleaseComObject(s); Marshal.FinalReleaseComObject(aDoc); Marshal.FinalReleaseComObject(d); // must quit app before releasing // again: casting because intellisense complained of ambiguity (wordApp as Word._Application).Quit(ref m, ref m, ref m); Marshal.FinalReleaseComObject(wordApp); 

Has intentado cambiar

 oWord.Visible = False 

a

 oWord.Visible = True 

?

Lo pregunto porque Word puede pedirte que hagas algo relacionado con esta plantilla que estás tratando de usar. Si cree que hay un cuadro de diálogo que muestra, normalmente no se apagará. IIRC, hay una manera de hacerlo, de modo que forme la opción Salir y no espere en ningún cuadro de diálogo. Pero, ha pasado un tiempo.

Solo he hecho automatización de Excel, pero me he encontrado con problemas similares. Al hacer referencia a un código antiguo, el último paso para cerrar tiene la línea GC.Collect ()

Este artículo también lo menciona: http://support.microsoft.com/kb/317109

Intenta llamar a GC.WaitForPendingFinalizers() y utiliza Marshal.FinalReleaseComObject lugar de Marshal.ReleaseComObject . Esto elimina la necesidad de repetirlo.

Actualiza tu código a esto y pruébalo (las llamadas GC están en el principio a propósito):

 GC.Collect() GC.WaitForPendingFinalizers() oDoc.Close() Marshal.FinalReleaseComObject(oDoc) Marshal.FinalReleaseComObject(oDocuments) oWord.Quit() Marshal.FinalReleaseComObject(oWord) 

También es posible que desee consultar esta pregunta relacionada sobre el tema de Excel.

Descubrí que el uso de Documents.Add () cuando se usa una plantilla personalizada es la culpable. No puedo explicar por qué esto dejaría colgado WinWord.exe. Sin embargo, hay otras formas de crear documentos a partir de plantillas que no generan el mismo problema.

Así que reemplacé:

 Dim doc As Word.Document = documents.Add(Template:=CObj(templatePath)) 

con:

 Dim doc As Word.Document = documents.Add() doc.AttachedTemplate = templatePath doc.UpdateStyles() 

Usar AttachedTemplate para especificar que la plantilla funciona para mí y no deja colgado WinWord.exe.

(Sin embargo, ha surgido un nuevo problema … Una imagen en el pie de página de la plantilla no se copia en el documento cuando se usa AttachedTemplate / UpdateStyles. Lo considero un tema aparte. Pero dado que este método resuelve mi problema original, Estoy satisfecho. ¡Gracias a todos los que ofrecieron respuestas!)

Obtuve el mismo problema cuando lo estaba haciendo:

 object missing = System.Reflection.Missing.Value; wordApplication.Quit(ref missing, ref missing, ref missing); 

Lo solucioné de esta manera:

 object objFalse = false; wordApplication.Quit(ref objFalse, ref objFalse, ref objFalse); 

No me preguntes por qué, la automatización de la oficina es una aventura 🙂

Me encontré con tu publicación debido a un problema similar con la plantilla. Me llegaba un mensaje que me pedía que guardara el archivo .dotm cada vez que intentaba cerrar la palabra en mi progtwig. No pude usar su respuesta aceptada porque no tengo una ruta de acceso de plantilla exacta, simplemente abro el documento que recibe el progtwig.

lo que yo uso es

 Word.NormalTemplate.Saved = true; 

cuando utilicé ese código antes de desechar la aplicación, ya no abriría el cuadro de diálogo diciendo que no había guardado la plantilla, y se ejecutaría sin dejar el proceso ” winWord.exe ” no deseado ejecutándose.

Recibí la sugerencia “NormalTemplate.Saved” del usuario ” NeedSomeAnswers ” en los foros visuales básicos aquí . En sus palabras “[it] no se guarda en la Normal, simplemente le dice a Word que la Normal ya se ha guardado para que no tenga que guardarla”.

Creo que esta es una segunda respuesta al mismo problema. Espero que ayude.

Que tengas un día maravilloso y que estés bien.

-nuevo día tu código funciona es un buen día para celebrar-

¿”oDocuments” tiene un método .Dispose () o .Close ()? estás desechando los otros 2, pero no este.

Aunque esto es C #, pero tal vez te ayude. Estoy usando este método para combinar varios documentos en uno solo. Paso todos los documentos en el Arraylist, y Word parece cerrarse correctamente cuando termina.

  public static void documentsMerge(object fileName, ArrayList arrayList) { // object fileName = Path.Combine(Environment.CurrentDirectory, @"NewDocument.doc"); File.Delete(fileName.ToString()); try { wordApplication = new ApplicationClass(); var doc = wordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing); try { doc.Activate(); int count = 0; foreach (var alItem in arrayList) { addDocument(alItem, doc, count == 0); count++; } // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc1.doc", doc ) ; //, false); // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc2.doc", doc ) ; //, true); doc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); } finally { doc.Close(ref missing, ref missing, ref missing); } } finally { wordApplication.Quit(ref missing, ref missing, ref missing); } } 

El bloque finally es útil para cleaning up cualquier recurso asignado en el bloque try así como para ejecutar cualquier código que deba ejecutarse incluso si hay una excepción. El control siempre pasa al bloque finally independientemente de cómo salga el bloque try.

Intenta poner tu código en el bloque try / finally y ve cómo se comporta entonces?

Para VB.NET

 Try ' Statement which can cause an exception. Catch x As Type ' Statements for handling the exception Finally End Try 'Any cleanup code 

No debe descartar el objeto de documento creado en Word.Documents.Add . Guarde y llame a Marshal.ReleaseComObject en cada objeto COM que obtenga de la automatización cuando haya terminado, es decir, si no almacena en caché los objetos en cualquier lugar .

 oWord.Visible = True 

Resolvió el problema para mí. El problema subyacente fue la recuperación de documentos. Apareció un diálogo a pesar de tener una línea:

 _wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone; 

Usé todos los trucos que se han mostrado aquí, pero hasta que se borró la lista de recuperación de documentos, se dejó un proceso de palabras “zombie” cada vez que se ejecutaba mi aplicación.

esta es una solución perfecta, tuve el mismo problema, acabo de seguir este y está funcionando perfecto.

objeto objFalse = falso;

wordApplication.Quit (ref objFalse, ref objFalse, ref objFalse);

Intenté automatizar la creación de un documento en word de vb.net, pero winword.exe aún se estaba ejecutando, incluso después de que cerré el documento. Encontré una solución a este problema; Moví el tenue de la palabra objeto al interior de la subrutina que estaba usando para editar el documento, en lugar de acotarlo independientemente de una subrutina (mi método inicial).

Espero que esto ayude.