2010-09-16 3 views
11

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

Доступ к Excel из приложения C# WinForms через COM Interop. С учетом объекта Excel.Application, как я могу:

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

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

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

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

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

+0

Используйте подушку, пожалуйста, кирпичи, как известно, довольно жесткие :) – Marko

+0

Возможно ли отслеживать событие Process.Exit и перезапустить Excel в скрытом состоянии, если пользователь закрыт вручную? –

+0

@Marko: Вы имеете в виду, что я не должен использовать Excel вообще? :-)/:-( – chiccodoro

ответ

7

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

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

Option Explicit 

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

Открыть Учебное пособие Alongwith других книг, которые вы имеете & не должны быть скрыта (если само приложение является невидимым).

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

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

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

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

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

+1

Этот подход звучит очень многообещающий, и его можно также использовать, чтобы быть замеченным в Quit, поскольку я могу заметить книгу-закрыть событие, наблюдая сборники книг (http://stackoverflow.com/questions/2767439/excel-automation-close-event-missing) – chiccodoro

+0

Привет шахкальпеш. Я пробовал, и все работает отлично! Мне так или иначе неудобно присуждать такой грязный подход, но на самом деле это единственный ответ, который действительно достигает того, что обсуждалось. – chiccodoro

+0

@chiccodoro: Да, это грязно. Если вам посчастливится найти лучший подход, не стесняйтесь публиковать его. Это, безусловно, поможет другим в попытке взломать :). Спасибо, что приняли ответ. – shahkalpesh

1

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

+0

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

+0

@ 'chiccodoro' - Вы можете (1) по-прежнему общаться через COM - использование' Process.Start' просто гарантирует, что Excel запущен. И (2) вы ничего не упомянули о пароле в своем вопросе, но вы сказали, что можете запустить его через 'Process.Start'. Возможно, вам нужно предоставить нам более подробную информацию? – Enigmativity

+0

Извините за то, что вы сбиваете с толку, уточните мой вопрос. – chiccodoro

5

В статье на английском языке есть статья КБ, How to automate Excel and then know the user closed it, на C++. Я не портировал это на C#, но, скорее всего, не так много работы.

+0

Если вы правильно очистите COMObjects с помощью «Marshal.ReleaseComObject», как отметил Отаку в своем ответе, процесс выйдет из onQuit. Освобождение объектов Office-Interop далее описано в этом вопросе: http://stackoverflow.com/questions/158706/how-to-properly-clean-up-excel-interop-objects-in-c У меня нет Excel- 2007 под рукой, поэтому я не уверен, что есть EventHandler для ApplicationQuit. Решение Process кажется вашим лучшим выбором. – marg

+0

Прошу прощения за то, что я был суровым. Был просто расстроен, чтобы попытаться изо всех сил сформулировать точный вопрос, набрать 150 рецентов за щедрость, а затем увидеть ответ, который был проголосован голосом, который не решает мою проблему и может помешать другим пользователям исследовать эту тему.- Я понял, что недоразумение исходит от того, что я не говорю, что мне нужны объекты все время, когда Excel работает, чтобы реагировать на события, и потому что, если Excel не уходит, я хочу, чтобы объект 'Application' повторно использовал его в следующий раз необходимо для повышения производительности. Тем не менее, я мог бы объединить ваше предложение с вариантом Саймона. – chiccodoro

+0

@chiccodoro: не проблема, основанная на чтении всех изменений, я вижу, что вы здесь. Я отредактировал выше с единственным известным решением от MSFT по этому вопросу. –

3

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

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

+0

Привет, Саймон. У вас есть кое-что. Вместо этого я мог бы также выбрать свойство 'Excel.Application.Visible'. Я не хотел использовать это до сих пор, потому что предположим, что макрос VBA по какой-либо причине устанавливает 'Visible = false', он распознает его как Quit. Хотя в сочетании с предложением Отаку это может быть многообещающим. – chiccodoro

+0

Это то, что делают приложения для тестирования белого ящика. Они используют вызовы Windows hook api для получения родительского окна и управления им с помощью мыши/клавиатуры автоматизации. Тем не менее, вы обнаружите проблемы с этим подходом ... например, выгрузка ресурсов после завершения процесса, в этом случае у вас могут быть проблемы с отключением добавок. –

3

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

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

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

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

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

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

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

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

+0

Возможно, существует еще одна опция «взлома», но для этого требуется заставить пользователя открывать свои книги в отдельном экземпляре Excel.exe, а затем убивать ссылки на этот экземпляр. –

+0

Привет, анонимный тип, спасибо за ваш сложный ответ! Ваше «введение» прекрасно говорит о том, что я пытался объяснить. Что касается 1, я не разработал надстройки, но они необходимы для работы с файлами, которыми управляет мое приложение. Все надстройки выгружаются Excel при выходе, т. Е. Если я возрожу этот Excel, они больше не доступны. Что касается 3, я попытался перезагрузить надстройки, но это не сработало и оказалось подверженным ошибкам. Что касается 2: проблема в том, что мне нужны объекты * до тех пор, пока работает Excel *, потому что я должен наблюдать некоторые события, например. BeforeSave, и скажите Cancel = true ... – chiccodoro

+0

ok Я понимаю, что вам нужно наблюдать за состоянием определенных событий, таких как BeforeSave и т. Д. Однако, если я предполагаю, что у вас есть приложение (внешнее по отношению к Excel.exe), работающее с мониторингом для этих событий в каждом экземпляре Excel вы можете не просто сериализовать и записать текущие состояния этих событий в файл config/xml, если этот экземпляр Excel.exe закрыт? Вы говорите, что у вас, предположительно, сценарий курицы n 'яйцо, связанный с событиями в Excel, но это не очень эффективный программный сценарий. В какой-то момент вы должны иметь возможность справиться с тем, что ваш пользователь отключен от Excel.exe –

-1

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

+1

Нет такого события, или, по крайней мере, я не могу его найти. Какую версию Excel вы имеете в виду? – chiccodoro

Смежные вопросы