worksheets workbook read office net microsoft manipular desde crear application .net vb.net excel

workbook - Excel 2007 se bloquea al cerrar a través de.NET



workbook worksheets vb net (3)

Encontré una solución en el Blog de MSDN Excel que funcionó para mí. Se explica como

Hay dos problemas con lo anterior:

(1) Aunque el código parece deshacerse primero del objeto ''wbkData'', etc., el código anterior en realidad no hace cumplir esto ya que el procedimiento .NET Garbage Collection puede deshacerse de sus objetos en cualquier orden. (GC no es determinista en orden, no solo no determinista en el tiempo).

(2) Comandos como ''wsh = wbkData.Workssheets.Item (1)'' - o líneas como esta - son muy comunes y crearán un objeto RCW envolviendo un objeto ''Hojas de trabajo''. No tendrá una variable que contenga una referencia, por lo que generalmente no piensa en ello, pero este objeto RCW no se eliminará hasta la próxima recolección de basura. Sin embargo, el código anterior llama a GC.Collect () al final , por lo que el RCW aún mantiene una referencia a este objeto ''Worksheets'' cuando se llama a appExcel.Quit (). Excel se bloquea como resultado.

El código final se ve como

GC.Collect() GC.WaitForPendingFinalizers() wbkData.Close(SaveChanges:=False) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wbkData) : wbkData = Nothing appExcel.Quit() System.Runtime.InteropServices.Marshal.FinalReleaseComObject(appExcel) : appExcel = Nothing

Tengo un programa .NET de Visual Basic que necesita abrir y cerrar una hoja de cálculo de Excel. Abrir y leer la hoja de cálculo funciona bien, pero al intentar cerrar la aplicación de Excel 2007 se cuelga. Parece cerrarse, pero si observa el administrador de tareas, la aplicación aún se está ejecutando. El código que estoy usando para cerrarlo es

wbkData.Close(saveChanges:=False) appExcel.Quit() wbkData = Nothing appExcel = Nothing

¿Cómo puedo hacer que Excel se cierre correctamente?


Escribí esa publicación que mencionaste en el blog del equipo de Excel ...

También discutí este tema previamente en para la pregunta Cómo limpiar adecuadamente los objetos de interoperabilidad de Excel en C # .

La primera respuesta para esa pregunta se marcó como "correcta" y obtuvo 11 votos, pero le aseguro que esa política es extremadamente difícil de utilizar correctamente en la práctica. Si alguna vez se desliza en cualquier lugar y utiliza "dos puntos", o itera celdas a través de un bucle o cualquier otro tipo similar de comando, entonces tendrá objetos COM sin referencia y se arriesgará a ser bloqueado, y no habrá forma de encuentra la causa de eso en el código.

En cambio, el procedimiento de limpieza que está adoptando es definitivamente el camino a seguir.


La respuesta a su pregunta se ha cubierto aquí. Creo que: cómo limpiar correctamente los objetos de interoperabilidad en c

No puedo ver desde la muestra de tu código, pero básicamente, siempre asignes tus objetos de Excel a las variables locales, nunca voy a ''dos ​​puntos hacia abajo'', como este:

//FAIL Workbook wkBook = xlApp.Workbooks.Open(@"C:/mybook.xls");

en su lugar ref cada obj individualmente:

//WIN Worksheets sheets = xlApp.Worksheets; Worksheet sheet = sheets.Open(@"C:/mybook.xls"); ... Marshal.ReleaseComObject(sheets); Marshal.ReleaseComObject(sheet);

.NET crea un contenedor para el objeto COM que es invisible para usted y no se libera hasta que el GC teje su magia.

Hasta que descubrí esto, estaba ejecutando el código hacky a continuación en una aplicación ASP.NET cada vez que creé un nuevo libro de trabajo que verifica la antigüedad del proceso excel.exe y elimina cualquiera que tenga más de un minuto de antigüedad:

//force kill any excel processes over one minute old. try { Process[] procs = Process.GetProcessesByName("EXCEL"); foreach (Process p in procs) { if (p.StartTime.AddMinutes(1) < DateTime.Now) { p.Kill(); } } } catch (Exception) {}