Просто еще одна проблема Excel COM
У меня есть приложение, которое импортирует данные из файла Excel. Он создает превосходный COM-объект и считывает данные из него. После этого я освобождаю все объекты и выпускаю все объекты Excel. Он делает все это на сервере Windows, используя Excel, установленный на этом компьютере. Файлы импорта хранятся на компьютерах пользователей.
Если я пытаюсь импортировать данные из файла, который также открыт в Excel на компьютере пользователя, приложение не может освободить COM-объекты Excel.
Любая идея, как я могу это исправить (закрыть этот экземпляр в любом случае)?
Спасибо!
Я добавил свой код:
public DataTable DoImportToDataTable(BackgroundWorker worker, string strPath, int columnCount, bool bIgnoreFirstLine = true)
{
bool importOk = false;
DataTable datatable = new System.Data.DataTable("ExcelContent");
Excel.Application excelApp = null; // the excel application instance
Excel.Workbook importFile = null; // the export workbook
Excel.Worksheet sheet = null; // the worksheet
Excel.Range range = null;
Excel.Sheets sheets = null;
try
{
excelApp = new Excel.Application();
excelApp.DisplayAlerts = false;
// try to open the file
importFile = excelApp.Workbooks.Open(strPath, Type.Missing, true, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
sheets = importFile.Worksheets;
sheet = (Excel.Worksheet)sheets.get_Item(1);
range = sheet.UsedRange;
int usedColumnsCount = range.Cells.Columns.Count;
int usedRowsCount = range.Cells.Rows.Count;
if (usedColumnsCount < columnCount)
{
throw new ImportException("Wrong file structure! Please check and correct the import file to match the requirements.");
}
Object[,] values = (Object[,])range.Value2;
data.Clear();
int row = 1;
// read data from used range
while (row <= usedRowsCount)
{
if (row == 1 && bIgnoreFirstLine)
{
row++;
continue;
}
if (worker.CancellationPending)
{
throw new Exception("Operation cancelled");
}
ArrayList line = new ArrayList();
bool bIsLineEmpty = true;
for (int i = 0; i < columnCount; i++)
{
if (values[row, i + 1] == null)
line.Add("");
else
{
line.Add((String)values[row, i + 1].ToString());
bIsLineEmpty = false;
}
}
if (bIsLineEmpty)
// return after first empty line in range
break;
datatable.Rows.Add(line.ToArray());
data.Add(line);
row++;
}
// cleanup
excelApp.DisplayAlerts = false;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
if (range != null) {
Marshal.FinalReleaseComObject(range);
range = null;
}
if (sheet != null) {
Marshal.FinalReleaseComObject(sheet);
sheet = null;
}
if (sheets != null)
{
Marshal.FinalReleaseComObject(sheets);
sheets = null;
}
if (importFile != null)
{
importFile.Close(Type.Missing, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(importFile);
importFile = null;
}
if (excelApp != null)
{
excelApp.Quit();
Marshal.FinalReleaseComObject(excelApp);
excelApp = null;
}
importOk = true;
}
catch (COMException e)
{
message = e.Message;
}
catch (ImportException e)
{
message = e.ImportMessage;
}
catch (Exception e)
{
message = e.Message;
}
finally
{
if (!importOk)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
if (range != null)
{
Marshal.FinalReleaseComObject(range);
range = null;
}
if (sheet != null)
{
Marshal.FinalReleaseComObject(sheet);
sheet = null;
}
if (sheets != null)
{
Marshal.FinalReleaseComObject(sheets);
sheets = null;
}
if (importFile != null)
{
importFile.Close(Type.Missing, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(importFile);
importFile = null;
}
if (excelApp != null)
{
excelApp.Quit();
Marshal.FinalReleaseComObject(excelApp);
excelApp = null;
}
}
}
return datatable;
}
2 ответа
Посмотрите здесь: Excel 2007 зависает при закрытии через.NET
Всегда присваивайте свои объекты Excel локальным переменным, никогда не опуская "две точки вниз", например так:
//fail
Workbook wkBook = xlApp.Workbooks.Open(@"C:\mybook.xls");
//win
Worksheets sheets = xlApp.Worksheets;
Worksheet sheet = sheets.Open(@"C:\mybook.xls");
...
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(sheet);
.NET создает оболочку для COM-объекта, которая невидима для вас и не освобождается до тех пор, пока GC не сотворит свою магию.
Я только что попробовал то, что вы описали, вот так:
_Application app = new Application();
Workbook wb = app.Workbooks.Open(@"C:\Users\josip.INCENDO\Desktop\Payment (uplate) - primjer.xls");
wb.Close();
wb = null;
app.Quit();
app = null;
И это прекрасно работает, даже если пользователь открыл документ. Вы можете опубликовать код, может быть?