2016-04-25 6 views
1

Мне сложно скрыть, что мои объекты COM закрываются, поэтому я не оставляю процесс EXCEL.EXE в фоновом режиме. Я узнал, что двойная точка и цепочка деклараций плохи, так как это может оставить объекты COM висящими вокруг.Как объявить Microsoft.Office.Interop.Excel.Worksheet, чтобы я мог закрыть его на C#?

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

worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[strName]; 

EDIT: Я попытался с помощью app.Quit(), когда я сделал выполнение этой линии, чтобы закрыть открытый объект Excel, однако это не работает. app.Quit() работает, если я вызываю его перед этой строкой.

ответ

4

Прежде всего, чтобы завершить процесс EXCEL.EXE, вам не нужно явно освобождать все COM-объекты, которые вы использовали. С помощью GC собираются завершенные в Runtime Wrappers (RCW), которые неявно создаются для среды выполнения .NET, когда вы получаете другую ссылку на COM-объект, и это освобождает базовые COM-объекты.

Все, что вам нужно сделать, это вызвать метод Quit, освободить ссылки RCW и дать GC собрать их.

//This runs the EXCEL.EXE process. 
Microsoft.Office.Interop.Excel.Application app = 
    new Microsoft.Office.Interop.Excel.Application(); 
//This locks the excel file either for reading or writing 
//depending on parameters. 
Microsoft.Office.Interop.Excel.Workbook book = app.Workbooks.Open(...); 

... 

//Explicitly closing the book is a good thing. EXCEL.EXE is alive 
//but the excel file gets released. 
book.Close(); 

//This lets the EXCEL.EXE quit after you release all your references to RCWs 
//and let GC collect them and thus release the underlying COM objects. 
//EXCEL.EXE does not close immediately after this though. 
app.Quit(); 
app = null; 

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

И, наконец, если вы хотите явно освободить RCW и соответствующие COM-объекты, чтобы свести к минимуму давление памяти во что бы то ни стало, вы можете явно вызвать GC для сбора RCW после того, как вы отпустите свои ссылки на них или даже явно опубликуете основные COM-объекты ДО GC собирают RCW. Будьте осторожны. Этот последний способ оставляет вас в ответе за то, что остальные RCW никогда не будут использоваться после этого или у вас будет исключение.

using Microsoft.Office.Interop.Excel; 
using System.Runtime.InteropServices; 

Application app = new Application(); 
Workbooks books = clsExcelApplication.Workbooks; 
Workbook book = books.Open("..."); 
Sheets sheets = book.Sheets; 
Worksheet sheet = sheets["..."]; 

... 

//Trying to be as explicit as we can. 
book.Сlose(); 

//Revese order. Using FinalReleaseComObject is even more dangerous. 
//You might release an object used inside excel 
//code which might lead to some dreadful internal exceptions. 
int remainingRefCount; 
remainingRefCount = Marshal.ReleaseComObject(sheet); 
remainingRefCount = Marshal.ReleaseComObject(sheets); 
remainingRefCount = Marshal.ReleaseComObject(book); 
remainingRefCount = Marshal.ReleaseComObject(books); 
app.Quit(); 
remainingRefCount = Marshal.ReleaseComObject(app); 

Имейте в виду. Если вы вручную освободить ссылки COM, чем срок службы EXCEL.EXE не зависит от RCWS и вы можете свести на нет их, когда вы хотите ...

sheet = null; 
sheets = null; 
book = null; 
books = null; 
app = null; 

В самом явном случае, не забудьте проверить возвращение из Marshal.ReleaseComObject. Если он не равен нулю, кто-то еще держит ссылку COM на ваш основной COM-объект, кроме RCW, который вы только что выпустили.

+0

Я нашел, пока вы убедитесь, что вы закрыли все, что вы обработали, и выпустили excelapp.Quit. Это действительно так. Я нашел некоторые проблемы в каком-то готовом экспортном кодексе, который я нашел, но также при установке excelapp = null в конце этого что ничто не висит на чем-то – BugFinder

+0

GC не выпускает компоненты COM. Вы должны явно это сделать. – Enigmativity

+1

@ Enigmativity GC не выпускает чистые COM-объекты, полученные через некоторый API, но он освобождает COM-объекты, полученные через Runtime Callable Wrappers. В случае с excel он полностью освобождает их. –