Principales respuestas
Controlar procesos

Pregunta
-
Hola, buenos días a todos.
Tengo una app que crea ciertos reportes en archivos Excels y me gustaría controlarlos a la hora de cerrarlos.
Cuando hago esto
Excel.Application xlApp = new Excel.Application();
se crea un proceso de Excel, el tema es que necesito, de alguna forma, obtener el Process ID de ese proceso Excel para luego más tarde cerrarlo.
Para cerrarlo hago esto
foreach (System.Diagnostics.Process proceso in System.Diagnostics.Process.GetProcesses()) { if (proceso.ProcessName == "EXCEL" || proceso.ProcessName == "excel") { proceso.Kill(); } }
pero el problema es que me cierra todos los procesos de excel, lo que necesito es cerrar uno en particular por su ID...
Cómo puedo obtener el Process ID de una aplicación abierta por el programa actual??? Hay alguna forma de poder lograr esto?
Muchas gracias a todos.
Saludos
Respuestas
-
Gracias por tu respuesta, mira, justamente tengo esto
private void CerrarObjeto(object obj) { try { //LIBERA TODOS LOS OBJETOS Y RECURSOS DEL EXCEL System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch (Exception) { obj = null; } finally { GC.Collect(); } }
pero no está funcionando, los procesos Excel siguen ejecutándose en el pc, por eso me gustaría forzar el cierre con un Kill pero al proceso en particular.
Saludos y gracias
- Propuesto como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46
- Marcado como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46
-
Estimados, lo resolví de la siguiente manera.
[DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId); if (xlApp != null) { int excelProcessId = -1; GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), ref excelProcessId); System.Diagnostics.Process ExcelProc = System.Diagnostics.Process.GetProcessById(excelProcessId); if (ExcelProc != null) { ExcelProc.Kill(); } }
Quizá no es la mejor forma y debería ser con ReleaseCOM pero funciona.
Muchas gracias.
Saludos.
- Marcado como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46
Todas las respuestas
-
No es el enfoque correcto. Lo adecuado es programar bien tu aplicacion de manera que cierre correctamente todos los objetos COM que cree mediante COM/Interop contra Excel. Si los destruyes correctamente, entonces el "reference counting" de COM detecta cuando el contador de usos llega a cero, y entonces cierra automaticamente el servidor COM (es decir, el Excel en este caso). Si esto se hace bien hecho, nunca se necesita el "Kill".
Esencialmente, lo que tienes que recordar es que hay que llamar a Marshall.ReleaseComObject por cada uno de tus objetos cuando termines de utilizarlo:
Worksheet hoja = xlApp.Worksheets.Open(...); ... Marshal.ReleaseComObject(hoja);
Esto tienes que repetirlo por cada uno de los objetos COM que crees en tu programa a partir de Excel (incluyendo el original xlApp). Si lo haces bien, sin olvidar ni un solo objeto, el Excel se cierra automaticamente en cuanto ejecutas el ReleaseComObject del ultimo de tus objetos. Haz una busqueda en Internet y encontraras muchisima informacion sobre este tema, ya que es algo frecuentisimo y super-conocido.
- Propuesto como respuesta Diana AcuñaModerator martes, 3 de diciembre de 2019 16:00
-
Gracias por tu respuesta, mira, justamente tengo esto
private void CerrarObjeto(object obj) { try { //LIBERA TODOS LOS OBJETOS Y RECURSOS DEL EXCEL System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch (Exception) { obj = null; } finally { GC.Collect(); } }
pero no está funcionando, los procesos Excel siguen ejecutándose en el pc, por eso me gustaría forzar el cierre con un Kill pero al proceso en particular.
Saludos y gracias
- Propuesto como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46
- Marcado como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46
-
justamente tengo esto [...] pero no está funcionando
Cuando no funciona, típicamente es porque se ha pasado por alto algún objeto sobre el que no se está llamando a CerrarObjeto. A veces no es evidente, sobre todo si escribes una expresión compleja que accede p.ej. a una celda de un rango de una hoja. Después de hacerlo, hay que liberar la celda, el rango y la hoja. No basta con hacer el "release" de la hoja pensando que eso libera todos los objetos dependientes de esa hoja.
El problema del kill es que no se sabe cuál es el Excel que está atendiendo tus peticiones COM. De hecho, es posible que un mismo servidor COM atienda peticiones de varios clientes COM, y por eso lleva el "conteo de conexiones" para desconectarse al cerrar la última. Si lo "mata" uno de los consumidores COM, puede "fastidiar" a los otros consumidores que estuviesen usando el objeto en ese momento.
- Propuesto como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46
-
Estimados, lo resolví de la siguiente manera.
[DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId); if (xlApp != null) { int excelProcessId = -1; GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), ref excelProcessId); System.Diagnostics.Process ExcelProc = System.Diagnostics.Process.GetProcessById(excelProcessId); if (ExcelProc != null) { ExcelProc.Kill(); } }
Quizá no es la mejor forma y debería ser con ReleaseCOM pero funciona.
Muchas gracias.
Saludos.
- Marcado como respuesta Pablo RubioModerator miércoles, 4 de diciembre de 2019 18:46