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

slhcrj9b  于 2023-02-13  发布在  其他
关注(0)|答案(3)|浏览(154)

我正在尝试关闭我的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进程。但是第一次触发SelectedIndexChanged事件时启动的第一个excel进程从未关闭。

    • 编辑:**

我自己已经贴出了一个答案,这是完成工作。但我会保持这个问题开放,如果万一有人想出更好的解决方案。

nvbavucw

nvbavucw1#

我有一个关闭Excel进程的解决方案。与其经历释放对象的痛苦,你可以杀死特定的Excel进程(如果你有多个打开的进程)。代码是:

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

namespace YourNameSpace
{
    public class MicrosoftApplications
    {
        [DllImport("user32.dll")]
        static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
        public class Excel
        {   
            public Excel()
            {
                Application = new Microsoft.Office.Interop.Excel.Application();
                RegisterExitEvent();
            }

            public Microsoft.Office.Interop.Excel.Application Application;
            
            private void RegisterExitEvent()
            {
                Application.WindowDeactivate -= XlApp_WindowDeactivate;
                Application.WindowDeactivate += XlApp_WindowDeactivate;
            }

            private void XlApp_WindowDeactivate(Workbook Wb, Window Wn)
            {
                Kill();
            }

            public void Kill()
            {
                int pid = 0;
                GetWindowThreadProcessId(Application.Hwnd, out pid);
                if (pid > 0)
                {
                    System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(pid);
                    p.Kill();
                }
                Application = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }
    }
}

你可以这样称呼它:YourNameSpace.MicrosoftApplications.Excel xlApp = new YourNameSpace.MicrosoftApplications.Excel();
通过调用xlApp.Application.whatever而不是xlApp.whatever来完成任何需要做的事情,如果用户退出excel窗口,它将杀死代码中使用的进程。如果您只想在后台生成一个报告,但不显示表单,那么只需调用xlApp.Kill();来结束该特定进程。

rks48beu

rks48beu2#

我已经找到了一个解决办法:

[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

b91juud3

b91juud33#

据我所知,ReleaseComObject会在您的C#应用程序退出时关闭Excel应用程序。因此,每次您调用FillSelectedItems()时,新的Excel进程都会显示在您的任务栏中,直到您退出C#应用程序时才会关闭。
编辑:在一个侧记,我建议使用
尝试,捕捉,最后
当处理Excel互操作库,主要是由于这样一个事实,即如果应用程序运行到一个异常,该程序将不会正常退出,并如前所述,它会导致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或garbagecollector,我相信你都无法摆脱这个问题。
编辑2:当然,另一种解决方法是搜索Excel进程ID并将其删除。我不建议这样做的原因是,如果运行此应用程序的用户已经在其计算机上运行了另一个Excel进程,则可能最终会删除该示例。

相关问题