Предотвратить выход из Excel - PullRequest
11 голосов
/ 16 сентября 2010

Мне не хватает события Excel.Application.Quit или Excel.Application.BeforeQuit. Кто-нибудь знает обходной путь для имитации этих событий?

Я получаю доступ к Excel из приложения C # WinForms через COM Interop.Учитывая объект Excel.Application, как я могу:

  1. Желательно предотвратить выход из Excel?
  2. Если это невозможно, как я могу, по крайней мере, заметить при выходе из Excel?

Обратите внимание: Поскольку у меня есть COM-ссылка на Excel.Application, , процесс Excel не завершается когда Excel «выходит» пользователем.Хотя это звучит противоречиво, но так оно и есть.Под «выходом» я подразумеваю, что пользователь нажимает «Выйти» или «крестик» в правом верхнем углу окна.Окно закрывается, файлы выгружаются, надстройки выгружаются и все, что делает Excel, кроме того, что я понятия не имею.Но я все еще могу использовать объект Application, чтобы «оживить» процесс и сделать Excel снова видимым, хотя надстройки тогда отсутствуют, и я не уверен, что еще находится в неопределенном состоянии.

Чтобы избавиться от этой проблемы, я хотел бы либо отменить выход в самом начале (подумайте о BeforeQuit Cancel = true, если он существовал), либо хотя бы получить уведомление о выходе из Excel, чтобы я мог выпуститьCOM-объекты и действительно завершают процесс, и в следующий раз, когда мне снова понадобится Excel, я буду знать, что мне нужно сначала запустить его.

К сожалению, это замкнутый круг: Пока работает Excel,Мне нужны объекты COM .Поэтому я не могу избавиться от них до того, как Excel выйдет.С другой стороны, пока есть COM-объекты, процесс не завершается, даже если Excel делает вид, что завершает работу, поэтому я не могу ждать события завершения процесса или чего-то подобного.

У меня неприятное чувствочто я собираюсь ударить головой о кирпичную стену ...

Ответы [ 6 ]

7 голосов
/ 28 сентября 2010

Обратите внимание, что я не пробовал это.

Создайте рабочую книгу с кодом на BeforeClose.
, например,

Option Explicit

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

Откройте эту книгу вместе с другими имеющимися у вас книгами, и это не обязательноскрытый (если все приложение невидимо).

Итак, если вы попытаетесь выйти из экземпляра Excel, это приведет к закрытию этой скрытой книги, что вызовет событие BeforeClose, и вы сможете написать код дляостановите его закрытие.

Обратите внимание, что приведенный выше код находится в VB6 (VBA), и его необходимо будет преобразовать в c #.
Если вы обнаружите какие-либо трудности с конвертированием, оставьте комментарий.вы хотите скрыть книгу, вы можете сделать

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

Примечание: книга имеет коллекцию Windows.Приведенный выше код пытается скрыть 1-е окно.
Не знаю, может ли книга иметь более 1 окна?если да, то как?

5 голосов
/ 22 сентября 2010

Есть статья в КБ, Как автоматизировать Excel, а затем узнать, что пользователь закрыл ее в C ++. Я не перенес это на C #, но это, вероятно, не так много работы.

3 голосов
/ 27 сентября 2010

Проблема, которую вы пытаетесь решить, не будет решена путем мониторинга выхода из программы.Прежде чем вы скажете, что я не отвечаю на ваш вопрос, вы утверждаете в вопросе, что вы можете восстановить Excel даже после того, как пользователь выйдет из Excel.Поэтому процесс excel.exe все еще находится в процессе, потому что у вас есть объект .net со ссылкой на взаимодействие com для взаимодействия с excel.application.

Итак, у вас есть три варианта:

  1. Избегайте выхода пользователя из Excel.Как вы заявили, удерживайте Excel от выхода из системы, однако я не знаю, как вы можете запретить пользователю вызывать выход из Excel, таким образом, как вы правильно заметили, выгружая свои и любые другие надстройки и т. Д. Имейте в виду, что Microsoft специально разрабатываетВзаимодействие с пользователем таким образом, они хотят, чтобы пользователи имели возможность закрыть свои приложения.Ваш плагин должен быть в состоянии справиться с этим, если он не может, я бы сказал, что это проблема с вашим плагином, а не Excel.Я могу ошибаться, поскольку я недостаточно знаю о требованиях ваших приложений.

  2. Очистите все неуправляемые ресурсы ДО того, как пользователь выйдет.Что вам нужно сделать, это очистить ваши ссылки на все неуправляемые ресурсы Excel и Office, прежде чем пользователь вручную выйдет из Excel, чтобы при выходе из кода вашего приложения не осталось каких-либо оставшихся ресурсов, которые теперь указывают на экземпляр Excel, который больше не работает.загружены дополнения и т. д.Шаг (а) следует выполнять по мере необходимости, как только вам больше не нужен конкретный ресурс или даже при повторном его использовании для чего-то другого (например, типа Excel.Range), тогда как шаг (b) следует использовать реже, однако, если егоВыигрышное приложение, а не надстройка, вероятно, намного чаще, все зависит от вашего приложения и того времени, которое у вас есть (время) до того, как пользователь сможет завершить выполнение своих задач и завершить работу.Очевидно, что с надстройкой вы можете просто поместить его в событие завершения работы или произвольно в своем коде.

    a.Как отметил Отаку, используйте Marshal.FinalReleaseCOMObject на каждом неуправляемом ресурсе, который после использования имеет значение! = Null.

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

    b.используйте шаблон очистки GC для ресурсов COM.

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    
  3. Перезагрузка надстроек Если вы не заинтересованы в полном отслеживании и выгрузке всех неуправляемых ресурсов из-за сложности этой задачи, ограничения по времени (хотя я бы порекомендовал это), вы можете посмотреть на перезагрузку любых необходимых надстроек, которые, по-видимому, уже известны в вашей среде.Это работает только если вы контролируете окружающую среду.Существуют способы загрузки надстроек Excel и COM вручную.Что касается других вещей, я не знаю об этом, но, возможно, это возможно, если вы используете XLL или, может быть, XLT в каталогах запуска / XLSTART, но это все равно будет загружаться.

3 голосов
/ 24 сентября 2010

Конечно, это хак, но вы не могли бы использовать Windows SetWindowsHookEx API с WH_SHELL или WH_CBT хотя бы для того, чтобы получать уведомление об уничтожении главного окна Excel?

ПРИМЕЧАНИЕ.то есть нужны некоторые права администратора для выполнения магии кросс-процесса.

1 голос
/ 16 сентября 2010

Почему бы вам просто не выполнить System.Diagnostics.Process.Start(@"SomeWorkbook.xlsx");, чтобы убедиться, что Excel запущен.Если он уже был запущен, это не создаст новый процесс.

0 голосов
/ 04 апреля 2011

Почему бы просто не использовать событие Application.ApplicationExit, чтобы узнать, когда оно закрыто?

...