Как очистить COM-ссылки в .NET, когда приложение будет запущено?
Я работаю над .NET-программой, которая запускает новый экземпляр Excel, выполняет некоторую работу, а затем завершает работу, но должна покинуть Excel. Позже, когда программа запустится снова, она попытается подключиться к предыдущему экземпляру.
Каков наилучший способ справиться с выпуском COM-объектов в этой ситуации? Если я не делаю «ReleaseComObject» в объекте приложения в первый раз, то во втором запуске получить активный объект, а затем, наконец, освободить объект com, у меня есть утечка памяти?
Следующий упрощенный код иллюстрирует то, что я пытаюсь сделать:
- Почему типизированный массив .NET не является общим типом? (т. е. SomeType ! = Array {SomeType})
- импортировать файлы txt с помощью excel interop в C # (QueryTables.Add)
- Может ли диапазон Range.Value2 и Range.Formula иметь разные значения в C #, а не VBA?
- Unspecified error (Исключение из HRESULT: 0x80004005 (E_FAIL)) в Microsoft.Office.Interop.Excel.ChartObject.Copy
- задержка вычислений excel во время взаимодействия C #
private Microsoft.Office.Interop.Excel.Application xlsApp; private Microsoft.Office.Interop.Excel.Workbook xlsWb; public void RunMeFirst() { //Start a new instance System.Type oSEType = Type.GetTypeFromProgID("Excel.Application"); xlsApp = Activator.CreateInstance(oSEType); xlsWb = xlsApp.Workbooks.Open("C:\\test1.xls"); //Do some stuff xlsWb.Close(false); Cleanup(ref xlsWb); //Do not quit Excel here //No Cleanup of xlsApp here? Is this OK? System.Environment.Exit(0); } public void RunMeSecond() { //Hook into existing instance xlsApp = Marshal.GetActiveObject("Excel.Application"); xlsWb = xlsApp.Workbooks.Open("C:\\test2.xls"); //Do some stuff xlsWb.Close(false); Cleanup(ref xlsWb); xlsApp.Quit(); Cleanup(ref xlsApp); System.Environment.Exit(0); } public void Cleanup(ref object theObj) { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); Marshal.FinalReleaseComObject(theObj); theObj = null; }
благодаря
- C # Excel.Interop Обнаружение действия сортировки
- Excel interop - как остановить номер (сохраненный как текст), который «оценивается»
- com interop: как потреблять c # из Excel или Access
- Ссылка Excel на .NET DLL ломается с новой версией
- VB.NET 64-битный COM с ссылочным классом сборки c #
- Как вычеркнуть текст в ячейке excel с помощью interop?
- Очистка объектов Excel Interop с помощью IDisposable
- Почему я получаю исключение COM при использовании FormulaArray
В общем, при работе с Office PIA я обнаружил, что подобные проблемы с не выпущенными объектами возникают, когда у вас есть переменные экземпляра, содержащие объекты COM. В вашем случае это будут xlsApp
и xlsWb
. Вам не нужно оставлять приложение Excel для освобождения объектов, но вам необходимо выполнить следующие процедуры очистки:
Marshal.FinalReleaseComObject(xlsWb); xlsWb = null; Marshal.FinalReleaseComObject(xlsApp); xlsApp = null; GC.Collect();
Локальные переменные, содержащие объекты COM, похоже, не вызывают этой проблемы, а только переменные экземпляра. Надеюсь, это поможет!
Я немного запутался – в конце RunMeFirst
вы выходите из процесса, а RunMeSecond
запускается в другом процессе из первого метода или того же процесса?
В любом случае я бы изменил ваш код так, чтобы xlsWb
локально и просто сделал следующее:
public void RunMeFirst() { System.Type oSEType = Type.GetTypeFromProgID("Excel.Application"); xlsApp = Activator.CreateInstance(oSEType); Workbook xlsWb = xlsApp.Workbooks.Open("C:\\test1.xls"); // Do stuff xlsWb.Close(false); System.Environment.Exit(0); }
Вы действительно не должны называть какие-либо из методов ReleaseComObject
кроме определенных обстоятельств (например, в серверных приложениях, где все COM-объекты будут использоваться, и поэтому очень важно как можно скорее освободить объекты). Обычный механизм очистки объекта COM должен просто состоять в том, чтобы позволить им выйти из области видимости, и в этом случае объект COM будет выпущен с использованием той же магии, которую использует GC (я считаю, что он очищается по мере запуска финализатора, но Я не уверен на этом на 100%).
Причина, по которой его хорошая идея в области xlsWb
локально (а не как член класса или статический член) состоит в том, что члены класса будут очищаться только после очистки класса, а статические члены никогда не будут очищены до тех пор, пока appdomain не будет выгружен. Если вам нужно очистить объект COM, на который ссылается статическое поле, то способ сделать это – установить для статического поля значение null
чтобы базовый COM-объект мог быть очищен правилами определения GC:
xlsWb = null;
Также не должно быть реальной необходимости называть GC.Collect
по тем же причинам – Майк Розенблюм дает справедливое объяснение, почему он вызывает GC.Collect
и ReleaseComObject
, но не имеет никакого реального обоснования того, почему он не просто удовлетворен тем, что позволяет мусору сборщик выполняет свою работу. Как я уже сказал, бывают ситуации, когда вам может потребоваться больше контроля над выпуском COM-объектов, однако это исключение, а не правило.
Вы также можете найти чтение Marshal.ReleaseComObject считается опасным полезным.