使用Excel Interop Com对象时无法使用“2点” - C#

时间:2012-10-25 12:59:01

标签: c# excel excel-interop

我在发布Excel Interop Com对象时遇到问题,当我尝试保存然后关闭通过Excel Interop创建的Excel工作簿时,导致我的c#应用程序崩溃。我觉得问题是在某些情况下我使用'2点'与excel互操作COM对象,这是我不读的。我已经从大多数代码行中删除了2个点,但我正在找到一种方法来重新创建以下代码行,以便它们只使用一个点。如果有人有任何建议我会非常感激。

workbook = (Excel.Workbook)app.Workbooks.Open(startForm.excelFileLocation,);

workbook = (Excel.Workbook)app.Workbooks.Add(1);

workSheet_range.Font.Color = System.Drawing.Color.FloralWhite.ToArgb();

workSheet_range.Font.Bold = font;

workSheet_range.Interior.Color = System.Drawing.Color.Red.ToArgb();

4 个答案:

答案 0 :(得分:3)

验证每条指令的返回类型并单独分解。

您的第一行以" app.Workbooks"开头返回Workbooks类型的对象。然后Open指令返回一个工作簿:

workbooks = app.Workbooks;
workbook = workbooks.Open(startForm.excelFileLocation);

然后您可以像这样拆分第二个:

workbook = workbooks.add(1);

如果您不是" dotting"可以使用多个点。实际的InterOp对象。

这是一个完整的样本:

Using Excel = Microsoft.Office.Interop.Excel;
public void Read()
{
    Excel.Application xlApp = new Excel.Application();
    Excel.Workbooks xlWorkBooks = xlApp.Workbooks;
    Excel.Workbook xlWorkBook = xlWorkBooks.Open(sourceFile);
    Excel.Worksheet xlWorkSheet = xlWorkBook.Worksheets[ 1 ];

    Excel.Range range = xlWorkSheet.UsedRange;
    range = range.Cells;
    Array myValues = ( Array )range.Value;    //now holds all the data in the sheet

    //The following is to ensure the EXCEL.EXE instance is released...
    //If you edit this code, know that using 2 dots (ex: range.Cells.Value) can create weird stuff!
    xlWorkBook.Close(false);
    xlWorkBooks.Close();
    xlApp.Quit();

    releaseObject(xlWorkSheet);
    releaseObject(xlWorkBook);
    releaseObject(xlWorkBooks);
    releaseObject(xlApp);

    xlWorkSheet = null;
    xlWorkBooks = null;
    xlWorkBook = null;
    xlApp = null;
}

private static void releaseObject( object obj )
{
try
{
    System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    obj = null;
}
catch (Exception ex)
{
    obj = null;
    Console.WriteLine("Unable to release the Object " + ex.ToString());
}
}

答案 1 :(得分:1)

总结这里的所有信息。

  1. 分配时不要使用两个点。
  2. 使用AutoReleaseComObject类。
  3. 使用Microsoft KB: Office application does not quit after automation from .NET client
  4. 中描述的ReleaseObject方法(使用while循环)
  5. 使用GC.Collect和GC.WaitForPendingFinalizers。
  6. 如果Excel进程在调试时保持活动状态,请不要感到惊讶,只需运行应用程序即可测试进程是否处于活动状态。
  7. 例如:

    using Microsoft.Office.Interop.Excel;
    ...
    var missing = Type.Missing;
    using (AutoReleaseComObject<Microsoft.Office.Interop.Excel.Application> excelApplicationWrapper = new AutoReleaseComObject<Microsoft.Office.Interop.Excel.Application>(new Microsoft.Office.Interop.Excel.Application()))
    {
        var excelApplicationWrapperComObject = excelApplicationWrapper.ComObject;
        excelApplicationWrapperComObject.Visible = true;
    
        var excelApplicationWrapperComObjectWkBooks = excelApplicationWrapperComObject.Workbooks;
        try
        {
            using (AutoReleaseComObject<Workbook> workbookWrapper = new AutoReleaseComObject<Workbook>(excelApplicationWrapperComObjectWkBooks.Open(@"C:\Temp\ExcelMoveChart.xlsx", false, false, missing, missing, missing, true, missing, missing, true, missing, missing, missing, missing, missing)))
            {
                var workbookComObject = workbookWrapper.ComObject;
                Worksheet sheetSource = workbookComObject.Sheets["Sheet1"];
                ChartObject chartObj = (ChartObject)sheetSource.ChartObjects("Chart 3");
                Chart chart = chartObj.Chart;
                chart.Location(XlChartLocation.xlLocationAsObject, "Sheet2");
    
                ReleaseObject(chart);
                ReleaseObject(chartObj);
                ReleaseObject(sheetSource);
    
                workbookComObject.Close(false);
            }
        }
        finally
        {
            excelApplicationWrapperComObjectWkBooks.Close();
            ReleaseObject(excelApplicationWrapperComObjectWkBooks);
    
            excelApplicationWrapper.ComObject.Application.Quit();
            excelApplicationWrapper.ComObject.Quit();
            ReleaseObject(excelApplicationWrapper.ComObject.Application);
            ReleaseObject(excelApplicationWrapper.ComObject);
    
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();    
        }
    }
    
    private static void ReleaseObject(object obj)
    {
        try
        {
            while (System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0);
            obj = null;
        }
        catch (Exception ex)
        {
            obj = null;
            Console.WriteLine("Unable to release the Object " + ex.ToString());
        }
    }
    

    我知道释放所有对象,使用GC.Collect并且在分配时不使用两个点似乎超过顶部至少当我退出Excel实例时,进程被释放,我不知道必须以编程方式杀死Excel进程!!

答案 2 :(得分:1)

我建议使用像 NetOffice 这样的库,它会为您释放所有资源(因此您不必担心所有这些COM Interop调用)作为奖励,会给你智能感知。

You can install it via NuGet或从网站下载程序集。

答案 3 :(得分:-1)

使用两个点并非“不允许”,但它肯定会对性能产生影响,尤其是在紧密循环中运行时。

每个“点”是对Excel库的COM调用,它可能比正常的CLR对象访问慢得多。通常,您希望将COM调用的数量减少到尽可能少。

通过分成两行来从两个点减少到一个不会对产生任何影响,除非重用相同的变量。例如,更改

workSheet_range.Interior.Color = System.Drawing.Color.Red.ToArgb();

var interior = workSheet_range.Interior;
interior.Color = System.Drawing.Color.Red.ToArgb();
如果您不重复使用interior变量,

将对性能产生 ZERO 影响,甚至可能会“优化”回原始单线程。

然而,改变

var font = workSheet_range.Font;
font.Color = System.Drawing.Color.FloralWhite.ToArgb();
font.Bold = font;

将减少对workSheet_range.Font的呼叫,因此您将看到增量收益。

BOTTOM LINE

我不会太担心更改每个两点调用,而是使用一个好的分析工具来确定代码花费最多时间的位置,然后首先处理该区域。