Как освободить COM-объекты в Silverlight 4 - PullRequest
6 голосов
/ 09 апреля 2011

При использовании COM-взаимодействия с Office (обычно Excel) я всегда тщательно проверяю, что я вызываю Marshal.ReleaseComObject при каждой ссылке, чтобы избежать проблемы, когда Excel не завершает работу , как описано в этой статье базы знаний .

Как обеспечить завершение работы Excel при использовании Interop из приложения OOB Silverlight (с AutomationFactory.CreateObject)?

В Silverlight нет метода Marshal.ReleaseComObject и даже вызова GC.Collectи GC.WaitForPendingFinalizers не помогает.

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

Удивительное упущение, тем более что Пит Браун в разделе 5.5 своей книги «Silverlight 4 в действии»доходит до того, что о AutomationFactory.CreateObject следует сказать, что:

Основной целью этой функции является обеспечение автоматизации других приложений, включая Microsoft Office.

ОБНОВЛЕНИЕ в ответ на комментарии Ганса.

Я не уверен, что проблема "тихого убийцы" существует в типичной автоматизации приложений Office.Обычное использование может выглядеть примерно так, как я часто видел в приложениях WinForms, не сталкиваясь с «отравленным RCW», описанным в статье, на которую ссылается Ганс:

  • Создание Excel.Экземпляр приложения
  • Открытие или создание рабочей книги
  • Запись данных в рабочую книгу
  • Показать Excel, если все прошло успешно, закрыть книгу и вызвать Application.Quit, если нет.
  • Вызовите Marshal.ReleaseComObject, чтобы освободить все ссылки на объекты Excel.

Если не вызвать Marshal.ReleaseComObject, как рекомендовано Хансом, будет запущено несколько копий Excel.exe, как описано в статье базы знаний.упомянутое выше - крайне нежелательно.

ОБНОВЛЕНИЕ 2

Образец, который я использую для воспроизведения этого примера, является примером из исходного кода книги Пита Брауна «Silverlight 4 в действии».На этой странице есть ссылка для скачивания.Пример решения AutomatingExcel находится в Ch05.zip / 5.03.Чтобы воспроизвести:

  • Убедитесь, что экземпляры Excel не запущены
  • Запустите образец AutomatingExcel
  • Открыта книга Excel
  • Закрыть Excel
  • Обратите внимание, с помощью диспетчера задач, что Excel все еще работает.

Установка всех динамических переменных на ноль и вызов GC.Collect (), кажется, работает, как указано в ответе AnthonyWJones.

ОБНОВЛЕНИЕ 2

Ответ Отаку - это то, что я искал - упаковывая ссылки в операторе using, ссылки COM освобождаются без необходимости вызывать GC.Collect.Немного экспериментов показывает, что более терпимо отказываться от каждой отдельной ссылки, в отличие от стандартного решения Marshal.ReleaseComObject, описанного в статье базы знаний, на которую мы ссылаемся выше.

Было бы интересно иметь авторитетное представление о том, что именнодолжен быть утилизирован, чтобы обеспечить освобождение всех ссылок Excel.

Ответы [ 4 ]

2 голосов
/ 13 мая 2011

Вы можете реализовать интерфейс IDisposable. Лучший пример этого я видел на http://csfun.blog49.fc2.com/blog-entry-79.html. Запись в блоге на японском языке, но откройте в Chrome и позвольте Google сделать перевод страницы для вас, если вы не читаете японский.

Кроме того, если вы просто хотите непосредственно получить пример исходного кода оболочки COM, вы можете загрузить образец приложения, в котором оно находится: SilverOffice .

1 голос
/ 13 мая 2011

Посмотрите на этот код: -

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        dynamic app = AutomationFactory.CreateObject("Excel.Application");
        dynamic book = app.Workbooks.Add();
        dynamic sheet = app.ActiveSheet();

        sheet = null;
        book.Close(false);
        book = null;
        app.Quit();
        app = null;

        GC.Collect();
    }

Процесс Excel появляется, а затем исчезает. Удалите GC, и процесс Excel продолжится. Вы получаете то же самое, если вы копируете этот код дословно? Если это так, то это предполагает, что где-то в вашем коде ссылка на объект Excel остается доступной из одного из стеков потоков или статических полей.

Вы когда-нибудь держали объект Excel в поле (в отличие от локальной переменной)?

Содержите ли вы объект Excel в том, что кажется переменным, но на него ссылается динамический делегат или лямбда-выражение, которое используется в качестве обработчика событий?

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

Многие из этих вещей могут помочь разработчикам оставить готовые объекты для GC, но GC находит их доступными и, следовательно, не подходящими для сбора.

Если приведенный выше код ведет себя не так, то мы ищем другую проблему полностью. Я использую Office 2007 на Server 2008 R2 с последней версии SL 4. Однако, если у нас есть изменения из-за настройки, то мы находимся на очень шаткой почве.

Редактировать

При некотором тестировании это кажется эффективным: -

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        using (dynamic app = AutomationFactory.CreateObject("Excel.Application"))
        {
            using (dynamic book = app.Workbooks.Add())
            {
                using (dynamic sheet = app.ActiveSheet())
                {

                }
                book.Close();
            }
            app.Quit();
        };

        GC.Collect();
    }

Однако не включайте GC, и в конечном итоге нежелательные процессы Excel останутся запущенными.

0 голосов
/ 10 августа 2012

путем включения ссылок в оператор using освобождаются ссылки COM

Обратите внимание: операторы using являются просто синтаксическим сахаром для try / catch / finally с Dispose () в предложении finally.

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

Критическая строка, которая здесь необходима, гласит:

((IDisposable)_excel).Dispose();  // Release COM Interface

Это предполагает:

dynamic _excel = AutomationFactory.CreateObject("Excel.Application");
0 голосов
/ 12 апреля 2011

Я хотел бы рассмотреть вопрос о создании файла Excel в службе WCF.Вы можете сделать всю уборку там.Отправка байтов в приложение Silverlight и использование SaveFileDialog для отправки их пользователю.

Silverlight имеет ограничение на доступ к файловой системе клиента.Работа с файлом Excel в клиентской системе или даже если предположить, что на клиенте установлен Excel, кажется нарушением этого.

...