如何在C#中正确关闭/处置Excel COM?(Excel进程未关闭)

时间:2014-11-14 08:38:42

标签: c# multithreading excel visual-studio com

是的,我知道,这也是互联网,也可能在这里,我跟着很多例子而且它仍然没有关闭,我真的厌倦了这个问题,拜托,如果有人能找到除杀死excel流程之外的其他解决方案,请通过分享来帮助我!

我的代码:

            #region ////////// Declarations and initialisations //////////

            string[] sFilesPath = System.IO.Directory.GetFiles(Path); // Get all files from current Path

            MSExcel.Application xlApp = null;
            MSExcel.Workbook xlWorkBook = null;
            MSExcel.Workbooks xlWorkBooks = null;
            MSExcel.Sheets xlSheets = null;
            MSExcel.Shapes xlShapes = null;
            MSExcel.Worksheet xlWorkSheet = null;
            MSExcel.Worksheets xlWorkSheets = null;

            xlApp = new MSExcel.Application(); xlApp.Visible = false; xlApp.DisplayAlerts = false;
            xlWorkBooks = xlApp.Workbooks;
            xlWorkBook = xlWorkBooks.Open(Path + _xlNamesList[i] + ".xlsx");
            xlSheets = xlWorkBook.Sheets;

            #endregion \\\\\\\\\\ Declarations and initialisations \\\\\\\\\\

            #region ////////// Clear all previous WorkSheets //////////

            foreach (MSExcel.Worksheet Worksheet in xlSheets)
            {
                Worksheet.Cells.Clear();
                foreach (MSExcel.Shape sh in Worksheet.Shapes)
                {
                    sh.Delete();
                    Marshal.ReleaseComObject(sh);
                }
            }
            if (xlSheets != null) Marshal.ReleaseComObject(xlSheets);

            #endregion \\\\\\\\\\ Clear all previous WorkSheets \\\\\\\\\\

            #region ////////// Insert each screenshot at it's respective location //////////

            foreach (string File in sFilesPath)
            {
                string sFileExtension = System.IO.Path.GetExtension(File);
                if (sFileExtension == ".jpg") // Insert each jpg file in it's coresponding place
                {
                    //--->  Declarations and initialisations
                    string sFileNameWitouthExtension = System.IO.Path.GetFileNameWithoutExtension(File),
                           sShiftName = sFileNameWitouthExtension.Substring(sFileNameWitouthExtension.Length - 7),
                           sLineName = sFileNameWitouthExtension.Substring(0, sFileNameWitouthExtension.Length - 8);

                    xlWorkSheet = xlWorkBook.Worksheets[sLineName]; // Get the coresponding worksheet to edit based on LineName

                    //--->  Place the screenshot in the Excel file based on sShiftName
                    if (sShiftName == "Shift 1")
                    {
                        xlWorkSheet.Cells[1, 4] = sFileNameWitouthExtension;
                        xlWorkSheet.Cells[1, 4].Font.Size = 30;
                        xlWorkSheet.Cells[1, 4].Rows.AutoFit();
                        xlWorkSheet.Cells[1, 4].Columns.AutoFit();

                        xlWorkSheet.Shapes.AddPicture(File, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 50, 40, 800, 500);
                    }
                    else
                        if (sShiftName == "Shift 2")
                        {
                            xlWorkSheet.Cells[40, 4] = sFileNameWitouthExtension;
                            xlWorkSheet.Cells[40, 4].Font.Size = 30;
                            xlWorkSheet.Cells[40, 4].Rows.AutoFit();
                            xlWorkSheet.Cells[40, 4].Columns.AutoFit();

                            xlWorkSheet.Shapes.AddPicture(File, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 50, 650, 800, 500);
                        }
                        else
                            if (sShiftName == "Shift 3")
                            {
                                xlWorkSheet.Cells[78, 4] = sFileNameWitouthExtension;
                                xlWorkSheet.Cells[78, 4].Font.Size = 30;
                                xlWorkSheet.Cells[78, 4].Rows.AutoFit();
                                xlWorkSheet.Cells[78, 4].Columns.AutoFit();

                                xlWorkSheet.Shapes.AddPicture(File, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 50, 1245, 800, 500);
                            }
                }
            }
            #endregion \\\\\\\\\\ Insert each screenshot at it's respective location \\\\\\\\\\

            #region ////////// Save EXCEL file and release/close objects //////////

            xlWorkBook.SaveAs(Path + _xlNamesList[i++] + ".xlsx", MSExcel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing, false, false, MSExcel.XlSaveAsAccessMode.xlNoChange, MSExcel.XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
            xlWorkBook.Close();
            xlApp.Quit();

            if (xlShapes != null) { Marshal.ReleaseComObject(xlShapes); xlShapes = null; }
            if (xlWorkSheet != null) { Marshal.ReleaseComObject(xlWorkSheet); xlWorkSheet = null; }
            if (xlWorkSheets != null) { Marshal.ReleaseComObject(xlWorkSheets); xlWorkSheets = null; }
            if (xlWorkBook != null) { Marshal.ReleaseComObject(xlWorkBook); xlWorkBook = null; }
            if (xlWorkBooks != null) { Marshal.ReleaseComObject(xlWorkBooks); xlWorkBooks = null; }
            if (xlApp != null) { Marshal.ReleaseComObject(xlApp); xlApp = null; }

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers();

            #endregion \\\\\\\\\\ Save EXCEL file and release/close objects \\\\\\\\\\

            #region ////////// Kill EXCEL proccess ---> DON'T WANT THIS!!! //////////

            foreach (Process Proc in Process.GetProcesses())
                if (Proc.ProcessName.Equals("EXCEL"))
                    Proc.Kill();

            #endregion \\\\\\\\\\ Kill EXCEL proccess \\\\\\\\\\

在我通过GC之后,Excel流程仍然存在:/,它已经让我疯狂了。请帮忙!!!

//编辑:感谢Hans将其标记为重复,另一篇文章FINALY回答了我的问题,所有tumb规则和点和对象发布都是废话,你只需要将GC放在外面一个不在里面的方法......

1 个答案:

答案 0 :(得分:1)

问题是您必须获取每个(中间)对象并在其上调用ReleaseComObject。否则你有一些不会被释放的东西,而且excel也不会关闭。

以下是导致这些问题的代码的一些不良示例:

 xlWorkSheet = xlWorkBook.Worksheets[sLineName];

有了你对Worksheets的悬空引用。最好这样写:

 xlWorkSheets = xlWorkBook.Worksheets;
 xlWorkSheet = xlWorkSheets[sLineName];

还有一个:

xlWorkSheet.Cells[40, 4].Rows.AutoFit();

这应该更好:

var cells = xlWorkSheet.Cells[40,4];
var rows = cells.Rows;
rows.AutoFit();

然后将所有这些中间对象放入HashSet<object>。最后,我将遍历此列表,并调用所有这些释放方法。

经验法则是:如果您的命令中有多个点,则说明错误。

为了找到这样的问题,我开始使用仅包含创建和关闭excel实例的包装器。然后我测试了excel打开并立即关闭。然后我开始慢慢访问一些对象并进行测试。在我添加的每两个新行之间,我测试了当我调用quit方法时excel仍然关闭。到目前为止,这是一种非常困难和令人沮丧的方式,但是唯一能够可靠地清理所有物体的方法。