2010-09-16 11 views
11

Me falta un evento Excel.Application.Quit o Excel.Application.BeforeQuit. ¿Alguien sabe una solución para imitar estos eventos?Impedir que Excel salga de

Accedo a Excel desde una aplicación C# WinForms a través de COM Interop. Dado un objeto Excel.Application, ¿cómo puedo:

  1. Prevenir de manera preferible que Excel se cierre?
  2. Si esto no es posible, ¿cómo puedo al menos observar cuando se cierra Excel?

Tenga en cuenta: Como no tengo una referencia COM a la Excel.Application, el proceso de Excel no se salida cuando Excel es "dejar de fumar" por parte del usuario. Aunque esto suena contradictorio, así es como es. Al decir "dejar de fumar" me refiero a que el usuario pulsa "Salir" o "botón cruzado" en la esquina superior derecha de la ventana. La ventana se cierra, los archivos se descargan, los complementos se descargan y todo lo que Excel hace aparte de lo que no tengo ni idea. Pero aún puedo usar el objeto Application para "revivir" el proceso y hacer que Excel vuelva a estar visible, aunque faltan los complementos, y no tengo certeza sobre qué más está en un estado indefinido.

para deshacerse de este problema, me gustaría que cancele el dejar de fumar en el primer momento (Piense en un BeforeQuitCancel = true si existiera), o al menos ser notificado cuando se salga de Excel, para que pueda liberar el COM objetos y hacer que el proceso realmente salga, y la próxima vez que necesite Excel nuevamente, sabré que necesito iniciarlo primero.

Desafortunadamente es un círculo vicioso: Mientras se ejecuta Excel, necesito los objetos COM. Así que no puedo deshacerme de ellos antes de Excel se cierra. Por otro lado, siempre que los objetos COM estén allí, el proceso no se cierra incluso si Excel finge que se cierra, por lo que no puedo esperar a que se produzca un evento de salida de proceso o similar.

tengo la sensación desagradable que voy a golpear la cabeza contra una pared de ladrillos ...

+0

Utilice una almohada, por favor, se sabe que los ladrillos son bastante duros :) – Marko

+0

¿Es una opción para supervisar el evento Process.Exit y reiniciar Excel en un estado oculto si el usuario lo cierra manualmente? –

+0

@Marko: ¿Quieres decir que no debería usar Excel en absoluto? :-)/:-( – chiccodoro

Respuesta

7

Tenga en cuenta que no he probado esto.

Cree un libro de trabajo que tenga código en él en BeforeClose.
por ej.

Option Explicit 

Private Sub Workbook_BeforeClose(Cancel As Boolean) 
    Cancel = True 
End Sub 

Abrir libro al igual que otros libros de trabajo que tiene & no debe limitarse al trabajo (si toda la aplicación es invisible).

Por lo tanto, si intenta salir de la instancia de Excel, forzará el cierre de este libro oculto, lo que elevará su evento BeforeClose & puede escribir código para evitar que se cierre.

Tenga en cuenta que el código anterior está en VB6 (VBA) y que tendrá que convertirse en C#.
Publique un comentario, si encuentra alguna dificultad para convertir.

Si desea ocultar un libro, que podría hacer

Workbooks("my workbook").Windows(1).Visible = False 

Nota: El libro tiene una colección Windows. El código anterior trata de ocultar la primera ventana.
No lo sé, ¿puede un libro de trabajo tener más de 1 ventana? ¿si es así, cómo?

+1

Este enfoque parece muy prometedor y también podría usarse para destacarse en Quit, porque puedo ver un libro cerrado evento mediante la observación de la colección de libros (http://stackoverflow.com/questions/2767439/excel-automation-close-event-missing) – chiccodoro

+0

Hola shahkalpesh. ¡Lo probé y funciona bien! Me siento un tanto incómodo al otorgar un enfoque tan sucio, pero de hecho es la única respuesta que realmente logra lo que se discutió. – chiccodoro

+0

@chiccodoro: Sí, está sucio. Si te encuentras con un mejor enfoque, no dudes en publicarlo. Eso seguramente ayudará a otros a probar el hack :). Gracias por aceptar la respuesta también. – shahkalpesh

1

¿Por qué no acaba de ejecutar una System.Diagnostics.Process.Start(@"SomeWorkbook.xlsx"); para asegurar que se inicia Excel. Si ya se ha iniciado, esto no creará un nuevo proceso.

+0

porque (1) Necesito comunicarme con el libro de trabajo a través de COM, y (2) necesito abrir el libro de trabajo con una contraseña programáticamente, para que el usuario no tenga que ingresarlo. – chiccodoro

+0

@ 'chiccodoro' - Usted puede (1) comunicarse a través de COM, utilizando' Process.Start' solo asegura que Excel se está ejecutando. Y (2) no mencionó nada sobre una contraseña en su pregunta, pero sí dijo que podría iniciarla a través de 'Process.Start'. ¿Quizás necesites darnos más detalles? – Enigmativity

+0

Perdón por confundirlo, actualizaré mi pregunta en consecuencia. – chiccodoro

5

Hay un artículo de KB, How to automate Excel and then know the user closed it, en C++. No he portado esto a C#, pero probablemente no sea mucho trabajo.

+0

Si limpia correctamente sus proyectos de COMO con 'Marshal.ReleaseComObject' como Otaku anotó en su respuesta, el proceso saldrá de Quit. La liberación de Office-Interop Objects se describe con más detalle en esta pregunta: http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects-in-c No tengo un Excel- Versión 2007 a la mano, así que no estoy seguro si hay un EventHandler para ApplicationQuit. La solución de proceso parece ser su mejor apuesta. – marg

+0

Lo siento por ser duro. Simplemente me sentí frustrado por hacer mi mejor esfuerzo para formular una pregunta precisa, una fracción de 150 repeticiones por una recompensa y luego ver que una respuesta se votó por encima, lo que no resuelve mi problema y puede evitar que otros usuarios investiguen en este hilo.- Me di cuenta de que el malentendido proviene de que no digo que necesito los objetos todo el tiempo Excel se ejecuta para reaccionar en los eventos, y porque si Excel no se cierra, quiero mantener el objeto 'Application' para reutilizarlo la próxima vez es necesario para mejorar el rendimiento. De todos modos, podría combinar tu propuesta con una variante de Simon tal vez. – chiccodoro

+0

@chiccodoro: no hay problema, basándome en leer todas las ediciones, estoy viendo más claro lo que estás buscando aquí. He editado lo anterior con la única solución conocida de MSFT sobre el tema. –

3

Es un truco, por supuesto, pero ¿no podría usar la API SetWindowsHookEx de Windows con WH_SHELL o WH_CBT al menos para recibir una notificación de destrucción de la ventana principal de Excel?

NOTA: Ciertamente tiene implicaciones de seguridad, es decir, necesita algunos derechos de administrador para realizar magia entre procesos.

+0

Hola Simon. Tienes algún punto allí. En su lugar, también podría optar por observar la propiedad 'Excel.Application.Visible'. No quería usar eso hasta el momento, porque supongamos que una macro de VBA establece 'Visible = falso' por cualquier razón, lo reconocería como Salir. Aunque, en combinación con la propuesta de Otaku, podría ser prometedor. – chiccodoro

+0

Esto es lo que hacen las aplicaciones de prueba de caja blanca. Utilizan las llamadas api de Windows para obtener la ventana primaria y controlarla mediante la automatización del mouse/teclado. Sin embargo, encontrarás problemas con este enfoque ... por ejemplo, la descarga de recursos una vez finalizado el proceso, en ese caso, es posible que aún tengas problemas con los complementos que están deshabilitados. –

3

El problema que está tratando de resolver aquí no se resolverá supervisando la salida del programa. Antes de decir que no estoy respondiendo su pregunta, afirma en la pregunta que puede reactivar la excelencia incluso después de que el usuario abandona Excel. Por lo tanto, el proceso excel.exe todavía está en juego porque tiene un objeto .net con una referencia de interoperabilidad com a excel.application.

Así que tienes tres opciones:

  1. evitar que el usuario sale de Excel. Como ha indicado, deje de dejar de Excel, pero desconozco la forma en que puede evitar que el usuario provoque el cierre de Excel, por lo que ha notado correctamente haber descargado su y cualquier otro complemento, etc. Tenga en cuenta que Microsoft específicamente diseñar la interacción del usuario de esta manera, quieren que los usuarios tengan la capacidad de cerrar sus aplicaciones. su complemento debe ser capaz de tratar con esto, si no puedo, diría que es un problema con su complemento no Excel. Podría estar equivocado ya que no sé lo suficiente acerca de los requisitos de sus aplicaciones.

  2. Limpiar todos los recursos no administrados ANTES de que el usuario cierre. Lo que debe hacer es limpiar sus referencias a todos los recursos no administrados de Excel y Office antes de que el usuario cierre manualmente Excel para que cuando lo dejen su código de aplicación no quede con recursos sobrantes que ahora apuntan a una instancia de Excel que no más tiempo tiene complementos, etc. cargados. El paso (a) debe realizarse sobre la marcha, tan pronto como ya no necesite un recurso en particular o incluso cuando lo reutilice para otra cosa (es decir, un tipo Excel.Range), mientras que el paso (b) se debe utilizar con menos frecuencia, sin embargo, si una aplicación para ganar y no un complemento, probablemente con mucha más frecuencia, todo depende de su aplicación y la ventana de oportunidad que tenga (tiempo) antes de que el usuario pueda completar sus tareas y cierre. Obviamente, con un complemento puede simplemente ponerlo en el evento de apagado o arbitrariamente en su código.

    a. Como señaló Otaku, use Marshal.FinalReleaseCOMObject en cada recurso no administrado que sea! = Null después de su uso.

    if (ComObject != null) 
        { 
         Marshal.FinalReleaseComObject(ComObject); 
         ComObject = null; 
        } 
    

    b. utilice el patrón de limpieza de GC para recursos COM.

    GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
    
  3. complementos Actualizar Si no estás interesado en el seguimiento de hasta el fondo y descarga de todos los recursos no administrados debido a la complejidad de esa tarea, a pesar de las limitaciones de tiempo (lo recomiendo), usted podría mirar a cualquier recarga necesaria complementos que presumiblemente ya conoce en su entorno. Esto solo funciona si controlas el ambiente. Existen técnicas para cargar complementos tanto de Excel como COM manualmente. En cuanto a otras cosas, no estoy al tanto de eso, pero tal vez sea posible si está usando XLL o XLT en directorios de arranque/XLSTART pero eso se cargaría de todos modos.

+0

Quizás haya otra opción de "hackeo", pero eso requiere forzar al usuario a abrir sus libros de trabajo en una instancia separada de Excel.exe y luego cancelar sus referencias a esa instancia. –

+0

Hola, tipo anónimo, gracias por tu respuesta elaborada! Tu "introducción" dice muy bien lo que he tratado de explicar. En cuanto a 1, no he desarrollado los complementos, pero se necesitan para trabajar con los archivos que administra mi aplicación. Excel finaliza la descarga de todos los complementos al salir, es decir, si reinicio ese Excel, ya no estarán disponibles. En cuanto a 3, traté de volver a cargar complementos, pero no funcionó y resultó ser propenso a errores. Respecto de 2: el problema es que necesito los objetos * siempre que Excel se esté ejecutando *, porque tengo que observar algunos eventos, p. BeforeSave event, y digamos Cancel = true ... – chiccodoro

+0

ok entiendo que necesita observar el estado de ciertos eventos como BeforeSave, etc., sin embargo, si asumo que tiene una aplicación (externa a Excel.exe) ejecutándose que está monitoreando para esos eventos en cada instancia de Excel, ¿no puede simplemente serializar y escribir los estados actuales de estos eventos en un archivo config/xml si esa instancia de Excel.exe está cerrada? Dice que supuestamente tiene un escenario de huevo de gallina con respecto a los eventos en Excel, pero este no es realmente un escenario de programa viable. En algún momento debe ser capaz de manejar el hecho de que su usuario no está conectado desde Excel.exe –

-1

¿Por qué no utilizar el evento Application.ApplicationExit para saber cuándo está cerrado?

+1

No hay tal evento, o al menos no puedo encontrarlo. ¿A qué versión de Excel te refieres? – chiccodoro

Cuestiones relacionadas