Предотвращение выхода из Excel

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

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

  • Желательно, чтобы Excel отказался?
  • Если это невозможно, как я могу хотя бы заметить, когда Excel закрывается?

Обратите внимание:. Поскольку у меня есть ссылка COM на Excel.Application, , процесс Excel не выходит из, когда пользователь "выйдет" из Excel. Хотя это звучит противоречиво, так оно и есть. Под "quit" я подразумеваю, что пользователь нажимает "Quit" или "cross button" в верхнем правом углу окна. Окно закрывается, файлы разгружаются, надстройки выгружаются и все, что делает Excel, кроме того, о чем я не знаю. Но я все еще могу использовать объект Application, чтобы "оживить" процесс и сделать Excel видимым снова, хотя надстройки отсутствуют, и я не уверен, что еще находится в состоянии undefined.

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

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

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

Ответ 1

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

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

Option Explicit

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

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

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

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

Если вы хотите скрыть книгу, вы можете сделать

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

    а. Как отметил Otaku, используйте Marshal.FinalReleaseCOMObject на каждом неуправляемом ресурсе, который равен = null после использования.

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

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

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

Ответ 5

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

Ответ 6

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