【问题标题】:Just another Excel COM issue只是另一个 Excel COM 问题
【发布时间】:2011-03-01 08:40:38
【问题描述】:

我有一个从 excel 文件导入数据的应用程序。它创建一个 excel COM 对象并从中读取数据。之后我释放所有对象并释放所有 excel 对象。 它使用安装在这台机器上的 excel 在 Windows 服务器上完成所有这些工作。导入文件存储在用户的机器上。

如果我尝试从用户机器上也在 Excel 中打开的文件导入数据,则应用无法释放 Excel COM 对象。

任何想法我该如何解决这个问题(无论如何都要关闭该实例)?

谢谢!

我已经添加了我的代码:

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;
    }

【问题讨论】:

    标签: c# excel com interop com-interop


    【解决方案1】:

    我刚刚试过你描述的,像这样:

            _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;
    

    即使用户打开了文档,它也能正常工作。可以发一下代码吗?

    【讨论】:

    • 我已经试过你的代码,只是注释掉了你正在对文件做的事情,它工作正常。我在任务管理器中使用 Excel => 打开文件,有 1 个 Excel 进程。我启动程序,它打开文件。 => 在任务管理器中有 2 个 Excel 进程。程序结束,关闭应用程序。 => 在任务管理器中有 1 个 Excel 进程。我关闭了 Excel 应用程序 => 任务管理器中没有 Excel 进程。
    • 感谢您的快速回复。我在本地得到相同的行为。问题是当应用程序在 Windows 服务器上运行并且文件在另一台机器上存储和打开时
    【解决方案2】:

    看看这里:Excel 2007 Hangs When Closing via .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 编织其魔法之前不会释放。

    【讨论】:

    • 谢谢!我知道这个问题,并将它们应用于我的代码。如果文件未在本地打开,则实例关闭没有问题。但是如果文件是打开的,这个实例就不能被关闭
    猜你喜欢
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-08-10
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多