c#Excel线程未完成(FinalReleaseComObject)

时间:2016-05-03 09:27:32

标签: c# excel

我有一个函数来读取Excel,然后是工作簿和工作表。 但Excel线程永远不会完成。我尝试了我在这里找到的所有解决方案,但没有用。

任务管理器上的Excel线程堆栈,此时,由于Excel停止工作,我的应用程序崩溃。

    public static object[,] ReadFile(string filepath, string sheetname)
    {
        Application xlApp = null;
        Workbooks wks = null;
        Workbook wb = null;
        object[,] values = null;
        try
        {
            xlApp = new ApplicationClass();
            wks = xlApp.Workbooks;
            wb = wks.Open(filepath, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);
            Worksheet sh = (Worksheet)wb.Worksheets.get_Item(sheetname);

            values = sh.UsedRange.Value2 as object[,];


            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sh);
            sh = null;

        }
        catch (Exception ex)
        {
            throw new Exception(string.Format("Sheet \"{0}\" does not exist in the Excel file", sheetname));
        }
        finally
        {

            if (wb != null)
            {

                wb.Close(false);
                Marshal.FinalReleaseComObject(wb);
                wb = null;
            }

            if (wks != null)
            {
                wks.Close();
                Marshal.FinalReleaseComObject(wks);
                wks = null;
            }

            if (xlApp != null)
            {
                // Close Excel.
                xlApp.Quit();
                Marshal.FinalReleaseComObject(xlApp);
                xlApp = null;
            }


        }

        return values;
    }

也许我不按正确的顺序做事,或者我理解错误的COM对象问题。

2 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,我在下面的代码中专门用来杀死进程

[DllImport("user32.dll")]
    static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

    Process GetExcelProcess(Excel.Application excelApp)
    {
        int id;
        GetWindowThreadProcessId(excelApp.Hwnd, out id);
        return Process.GetProcessById(id);
    }

此方法GetExcelProcess将为您提供可以手动终止的确切过程。它将从任务管理器中删除Excel.exe。

答案 1 :(得分:1)

根据我的理解,如果使用像excel interop这样的.NET包装器对象,则不必显式释放com对象。如果excel仍然存在,那么我会在处理中寻找错误,因为可能会留下一些东西 在下面的示例中,excel进程在第一个console.ReadLine时已停止。如果它没有立即停止尝试按Enter键启动GC。

以下为我和excel的工作已停止 我用过:
.NET Framework 4.5.2
Microsoft.Office.Interop.Excel 1.7.0.0
Excel 2010
Windows 7

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Go");
            var t = ReadFile(@"<filename>", "<sheetname>");
            Console.WriteLine("1");
            Console.ReadLine();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            Console.ReadLine();
        }


        public static object[,] ReadFile(string filepath, string sheetname)
        {
            Application xlApp = null;
            Workbooks wks = null;
            Workbook wb = null;
            object[,] values = null;
            try
            {
                xlApp = new Application();
                wks = xlApp.Workbooks;
                wb = wks.Open(filepath);
                Worksheet sh = (Worksheet)wb.Worksheets.get_Item(sheetname);

                values = sh.UsedRange.Value2 as object[,];

                //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sh);
                //sh = null;

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(string.Format("Sheet \"{0}\" does not exist in the Excel file", sheetname));
            }
            finally
            {

                if (wb != null)
                {

                    wb.Close(false);
                    //Marshal.FinalReleaseComObject(wb);
                    wb = null;
                }

                if (wks != null)
                {
                    wks.Close();
                    //Marshal.FinalReleaseComObject(wks);
                    wks = null;
                }

                if (xlApp != null)
                {
                    // Close Excel.
                    xlApp.Quit();
                    //Marshal.FinalReleaseComObject(xlApp);
                    xlApp = null;
                }


            }

            return values;
        }
    }

}

作为对不使用两个点命令的链接stackoverflow问题的注释。这个示例在我的机器上也可以使用两个点命令(打开工作簿)。它没有任何区别。 Excel已发布,流程已关闭。用于测试的Excel工作表是一个标准工作表,其中3个字段填入数字。