能够关闭除第一个实例之外的所有excel进程

时间:2016-09-01 06:59:27

标签: c# .net excel winforms interop

我正在尝试在winform应用程序中关闭excel进程。我在SO和其他网站上经历过很多帖子,这就是我现在正在做的事情:

private void lsvSelectedQ_SelectedIndexChanged(object sender, EventArgs e)
        {
          FillSelectedItems();
        }

private void FillSelectedItems()
        {
            string filepath = string.Empty;
            string reportname = lblreportname.Text;
            filepath = Application.StartupPath + "\\StandardReports\\" + reportname + ".xls";

            Microsoft.Office.Interop.Excel.Application xlApp;
            Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
            Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
            object misValue = System.Reflection.Missing.Value;

            xlApp = new Microsoft.Office.Interop.Excel.Application();
            xlWorkBook = xlApp.Workbooks.Open(filepath, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
            List<string> WorksheetList = new List<string>();          

            xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets.get_Item("Config");

            Microsoft.Office.Interop.Excel.Range objRange = null;

            objRange = (Microsoft.Office.Interop.Excel.Range)xlWorkSheet.Cells[6, 2];
            if (objRange.Value != null)
            {
                int intSheet =  Convert.ToInt32(objRange.Value);

                for (int i = 0; i < intSheet; i++)
                {
                    objRange = (Microsoft.Office.Interop.Excel.Range)xlWorkSheet.Cells[6, 3+i ];
                    if (objRange.Value != null)
                    {
                        lsvSelectedQ.Items.Add(Convert.ToString(objRange.Value));
                    }
                }
            }           

           ReleaseMyExcelsObjects(xlApp, xlWorkBook, xlWorkSheet);           
        }

在上面的代码中,我使用ReleaseMyExcelsObjects方法来摆脱任务栏中运行的excel进程。

  private void ReleaseMyExcelsObjects(Microsoft.Office.Interop.Excel.Application xlApp, Microsoft.Office.Interop.Excel.Workbook xlWorkBook, Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet)
        {
            xlApp.DisplayAlerts = false;
            xlWorkBook.Save();
            xlWorkBook.Close();
            xlApp.DisplayAlerts = false;
            xlApp.Quit();
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkSheet);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBook);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
            xlWorkSheet = null;
            xlWorkBook = null;
            xlApp = null;
            GC.Collect();
        }

正如您所看到的,我在SelectedIndexChanged上打开了一个excel,我也尝试通过ReleaseMyExcelsObjects()方法关闭该过程,除了生成的第一个excel进程外,它仍然有效。我的意思是当事件被触发时,excel进程被启动并且ReleaseMyExcelsObjects()没有关闭它,但是第二次SelectedIndexChanged被触发时,另一个excel进程被启动。这次ReleaseMyExcelsObjects()关闭了第二个excel流程。但是第一次触发theSelectedIndexChanged事件时启动的第一个excel进程永远不会被关闭。

修改

我自己发布了一个答案,即完成工作。但是如果有人想出更好的解决方案,我会打开这个问题。

2 个答案:

答案 0 :(得分:0)

根据我的理解, ReleaseComObject 会在您的C#应用程序退出时关闭Excel应用程序。因此,每次调用 FillSelectedItems()时,新的Excel流程都会显示在您的任务栏中,直到您退出C#应用程序时,它才会关闭。

编辑:在旁注中,我建议在处理excel互操作库时使用 try,catch,finally ,这主要是因为如果应用程序遇到异常,程序将不会正常退出,如前所述,它将导致任务栏中保留excel进程(当你在excel上手动打开所述文件时,它会告诉你最后恢复的版本blablabla)

string filepath = string.Empty;
        string reportname = lblreportname.Text;
        filepath = Application.StartupPath + "\\StandardReports\\" + reportname + ".xls";

        Microsoft.Office.Interop.Excel.Application xlApp;
        Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
        Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
        object misValue = System.Reflection.Missing.Value;

        xlApp = new Microsoft.Office.Interop.Excel.Application();
        xlWorkBook = xlApp.Workbooks.Open(filepath, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
        List<string> WorksheetList = new List<string>();

        try
        {
            //Your code
        }
        catch (Exception ex) { MessageBox.Show(string.Format("Error: {0}", ex.Message)); }
        finally
        {
            xlWorkBook.Close(false, filepath, null);
            Marshal.ReleaseComObject(xlWorkBook);
        }

老实说,如果你对此感到恼火,我建议使用EPPlus或ExcelDataReader(这只是用于阅读excel电子表格)作为替代库。否则,无论你添加多少个releaseComObjects或者垃圾收集器,我相信你都不会摆脱这个问题。

编辑2:当然,另一种解决方法是搜索Excel进程ID并将其终止。我不推荐这个的原因是因为如果运行此应用程序的用户已经在他的计算机上运行了另一个excel进程,那么最终可能会杀死该实例。

答案 1 :(得分:0)

我找到了解决这个问题的方法:

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

        public static Process GetExcelProcess(Microsoft.Office.Interop.Excel.Application excelApp)
        {
            int id;
            GetWindowThreadProcessId(excelApp.Hwnd, out id);
            return Process.GetProcessById(id);
        }

将其用作classobj.GetExcelProcess(xlApp).Kill();

取自:https://stackoverflow.com/a/15556843/2064292