.net - studio - editar documento word visual basic
WinWord.exe no se cerrará después de llamar a Word.Documents.Add-Word.NET Interop (13)
¿tiene "oDocuments" un método .Dispose () o .Close ()? estás desechando los otros 2, pero no este.
Me estoy ejecutando en el escenario clásico donde, al crear objetos COM de Word en .NET (a través del ensamblado Microsoft.Office.Interop.Word), el proceso de WinWord no se cerrará aunque esté cerrando y liberando correctamente los objetos .
Lo he reducido al uso del método Word.Documents.Add (). Puedo trabajar con Word de otras maneras sin problemas (abrir documentos, modificar contenidos, etc.) y WinWord.exe se cierra cuando se lo ordeno. Una vez que uso el método Add () (y solo al agregar 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 hacer un bucle Marsha.ReleaseComObject hasta que devuelva el código correcto. Trabajar con los objetos de Word está bien en otros aspectos, es solo la molesta Documentos. Agregue lo que me está causando dolor. ¿Hay otro objeto que se crea en este proceso que necesito referenciar y eliminar? ¿Hay otro paso de eliminación que necesito 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:
he reducido 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 a Add () sin parámetros, el problema no se produce.
(Todos mis consejos se adaptan de esta respuesta sobre la interoperabilidad de Excel).
Hay algunas cosas importantes aquí:
1) Nunca use 2 puntos en la misma línea. También considere un indexador como un punto
Bueno
Word.Documents d = wordApp.Documents;
Word.Document aDoc = d.Open(/*...*/);
MALO
Word.Document aDoc = wordApp.Documents.Open(/*...*/);
2) Suelte todos sus punteros.
3) No, regresa y suelta todos tus punteros, perdiste uno en algún lugar (o al menos siempre lo hago).
Aquí hay un ejemplo completo de lo que FINALMENTE me funcionó en un proyecto después de muchos lamentos y crujir 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);
Aunque esto es C # pero quizás te ayude. Estoy usando este método para combinar varios documentos en uno. Paso todos los documentos en Arraylist, y Word parece cerrar correctamente cuando se hace.
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
recursos asignados en el bloque try, así como para ejecutar cualquier código que deba ejecutarse incluso si hay una excepción. El control siempre se pasa al bloque finally, independientemente de cómo salga el bloque try.
Entonces, ¿intenta poner tu código en el bloque try / finally y ver 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
Descubrí que la culpa es del uso de Documents.Add () cuando se usa una plantilla personalizada . No puedo explicar por qué esto dejaría WinWord.exe colgado. Sin embargo, hay otras formas de crear documentos a partir de plantillas que no resultan en 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()
El uso de AttachedTemplate para especificar 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 al documento cuando se usa AttachedTemplate / UpdateStyles. Lo estoy considerando como un tema separado. Pero como este método resuelve mi problema original, Estoy satisfecho. Gracias a todos los que ofrecieron respuestas!)
Esta es una solución perfecta, tuve el mismo problema, simplemente seguí esta y está funcionando a la perfección.
objeto objFalse = falso;
wordApplication.Quit (ref objFalse, ref objFalse, ref objFalse);
Has intentado cambiar
oWord.Visible = False
a
oWord.Visible = True
?
Le pregunto porque es posible que Word le pida que haga algo relacionado con esta plantilla que está tratando de usar. Si cree que se está mostrando un diálogo, normalmente no se apagará. IIRC, hay una manera de dejar de fumar de manera que lo obligue a salir y no esperará ningún diálogo. Pero, ha sido un tiempo.
Intenté automatizar la creación de un documento en Word desde vb.net, pero winword.exe todavía se estaba ejecutando, incluso después de cerrar el documento. Me encontré con una solución a este problema; Moví el tenue objeto de la palabra al interior de la subrutina que estaba usando para editar el documento, en lugar de dimensionarlo independientemente de una subrutina (mi método inicial).
Espero que esto ayude.
Intente llamar a GC.WaitForPendingFinalizers()
y usar Marshal.FinalReleaseComObject
lugar de Marshal.ReleaseComObject
. Esto elimina la necesidad de bucle.
Actualice su código a esto y pruébelo (las llamadas del GC son al principio a propósito):
GC.Collect()
GC.WaitForPendingFinalizers()
oDoc.Close()
Marshal.FinalReleaseComObject(oDoc)
Marshal.FinalReleaseComObject(oDocuments)
oWord.Quit()
Marshal.FinalReleaseComObject(oWord)
También puede consultar esta pregunta relacionada que trata el problema de Excel.
Me encontré con su publicación debido a un problema similar con la plantilla. Me gustaría recibir un mensaje que me pide que guarde el archivo .dotm cada vez que intente cerrar la palabra en mi programa. No pude usar su respuesta aceptada porque no tengo una ruta de plantilla exacta, simplemente abro cualquier documento que reciba el programa.
lo que utilicé es
Word.NormalTemplate.Saved = true;
cuando utilicé ese código antes de deshacerme de la aplicación, ya no aparecería el cuadro de diálogo que decía que no había guardado la plantilla, y se ejecutaría la eliminación sin dejar el proceso " winWord.exe " no deseado en ejecución.
Obtuve el consejo "NormalTemplate.Saved" del usuario " NeedSomeAnswers " en los foros básicos visuales here . En sus palabras "[it] no se guarda realmente en la Normal, solo le dice a Word que la Normal ya se ha guardado, por lo que no necesita guardarlo".
Creo que esta es una segunda respuesta al mismo problema. Espero que ayude.
Que tengas un día increíble, y que estés bien.
-cualquier día su código funcione es un buen día para celebrar-
Solo he hecho la automatización de Excel, pero me he encontrado con problemas similares. Haciendo 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
Tengo el mismo problema cuando lo estaba haciendo:
object missing = System.Reflection.Missing.Value;
wordApplication.Quit(ref missing, ref missing, ref missing);
Resolví de esta manera:
object objFalse = false;
wordApplication.Quit(ref objFalse, ref objFalse, ref objFalse);
No me preguntes por qué, automatizar la oficina es una aventura :)
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 termine, es decir, si no almacena en caché los objetos en ningún lugar .
oWord.Visible = True
Resolví el problema por mí. El problema subyacente era la recuperación de documentos. Aparecía un diálogo a pesar de tener una línea:
_wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
Utilicé todos los trucos que se han mostrado aquí, pero hasta que se eliminó la lista de recuperación de documentos, se dejó un proceso de "zombie" cada vez que se ejecutaba mi aplicación.