首页 文章

数据访问后在C#中关闭Excel应用程序进程

提问于
浏览
64

我正在用C#编写一个应用程序,它打开一个用于读/写操作的Excel模板文件 . 我想当用户关闭应用程序时,excel应用程序进程已关闭,而不保存excel文件 . 多次运行应用程序后,请参阅我的任务管理器 .

enter image description here

我使用此代码打开excel文件:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");

对于数据访问,我使用以下代码:

Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

我在stackoverflow中看到类似的问题,如this questionthis,以及测试答案,但它不起作用 .

15 回答

  • 0

    想一想,它会杀死这个过程:

    System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel");
    foreach (System.Diagnostics.Process p in process)
    {
        if (!string.IsNullOrEmpty(p.ProcessName))
        {
            try
            {
                p.Kill();
            }
            catch { }
        }
    }
    

    另外,你试过正常关闭吗?

    myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
    excelBook.Close(null, null, null);                 // close your workbook
    excelApp.Quit();                                   // exit excel application
    excel = null;                                      // set to NULL
    
  • 8

    试试这个:

    excelBook.Close(0); 
    excelApp.Quit();
    

    关闭工作簿时,您有三个可选参数:

    Workbook.close SaveChanges, filename, routeworkbook
    

    Workbook.Close(false) 或者如果你正在进行后期绑定,有时候更容易使用零 Workbook.Close(0) 这就是我在自动关闭工作簿时的表现 .

    我也去找了它的文档,在这里找到了:Excel Workbook Close

    谢谢,

  • 3
    xlBook.Save();
    xlBook.Close(true);
    xlApp.Quit();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
    

    尝试这个..它对我有用...你应该释放xl应用程序对象来停止进程 .

  • 0

    参考:https://stackoverflow.com/a/17367570/132599

    避免使用双点调用表达式,例如:var workbook = excel.Workbooks.Open(/ * params * /)
    ...因为通过这种方式,您不仅可以为工作簿创建RCW对象,还可以为Workbooks创建RCW对象,并且也应该释放它(如果不维护对象的引用,这是不可能的) .

    这解决了我的问题 . 您的代码变为:

    public Excel.Application excelApp = new Excel.Application();
    public Excel.Workbooks workbooks;
    public Excel.Workbook excelBook;
    workbooks = excelApp.Workbooks;
    excelBook = workbooks.Add(@"C:/pape.xltx");
    
    ...
    
    Excel.Sheets sheets = excelBook.Worksheets;
    Excel.Worksheet excelSheet = (Worksheet)(sheets[1]);
    excelSheet.DisplayRightToLeft = true;
    Range rng;
    rng = excelSheet.get_Range("C2");
    rng.Value2 = txtName.Text;
    

    然后释放所有这些对象:

    System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
    excelBook .Save();
    excelBook .Close(true);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
    excelApp.Quit();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
    

    我将它包装在一个 try {} finally {} 中,以确保即使出现问题(可能出错的地方,一切都会被释放),例如

    public Excel.Application excelApp = null;
    public Excel.Workbooks workbooks = null;
    ...
    try
    {
        excelApp = new Excel.Application();
        workbooks = excelApp.Workbooks;
        ...
    }
    finally
    {
        ...
        if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
        excelApp.Quit();
        System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
    }
    
  • 19

    杀死Excel并不总是那么容易;看到这篇文章:50 Ways to Kill Excel

    本文从微软(MS Knowlege Base Article)上获得了关于如何让Excel好好退出的最佳建议,但是如果有必要,还可以通过终止进程来确保它 . 我喜欢第二个降落伞 .

    确保关闭所有打开的工作簿,退出应用程序并释放xlApp对象 . 最后检查过程是否仍然存在,如果是,那么杀死它 .

    本文还确保我们不会终止所有Excel进程,但只会杀死已启动的确切进程 .

    另见Get Process from Window Handle

    这是我使用的代码:(每次都有效)

    Sub UsingExcel()
    
        'declare process; will be used later to attach the Excel process
        Dim XLProc As Process
    
        'call the sub that will do some work with Excel
        'calling Excel in a separate routine will ensure that it is 
        'out of scope when calling GC.Collect
        'this works better especially in debug mode
        DoOfficeWork(XLProc)
    
        'Do garbage collection to release the COM pointers
        'http://support.microsoft.com/kb/317109
        GC.Collect()
        GC.WaitForPendingFinalizers()
    
        'I prefer to have two parachutes when dealing with the Excel process
        'this is the last answer if garbage collection were to fail
        If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
            XLProc.Kill()
        End If
    
    End Sub
    
    'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
    <System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
        Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
        ByRef lpdwProcessId As Integer) As Integer
    End Function
    
    Private Sub ExcelWork(ByRef XLProc As Process)
    
        'start the application using late binding
        Dim xlApp As Object = CreateObject("Excel.Application")
    
        'or use early binding
        'Dim xlApp As Microsoft.Office.Interop.Excel
    
        'get the window handle
        Dim xlHWND As Integer = xlApp.hwnd
    
        'this will have the process ID after call to GetWindowThreadProcessId
        Dim ProcIdXL As Integer = 0
    
        'get the process ID
        GetWindowThreadProcessId(xlHWND, ProcIdXL)
    
        'get the process
        XLProc = Process.GetProcessById(ProcIdXL)
    
    
        'do some work with Excel here using xlApp
    
        'be sure to save and close all workbooks when done
    
        'release all objects used (except xlApp) using NAR(x)
    
    
        'Quit Excel 
        xlApp.quit()
    
        'Release
        NAR(xlApp)
    
    End Sub
    
    Private Sub NAR(ByVal o As Object)
        'http://support.microsoft.com/kb/317109
        Try
            While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
            End While
        Catch
        Finally
            o = Nothing
        End Try
    End Sub
    
  • 73

    excelBook.Close(); excelApp.Quit();添加代码的结尾,就足够了 . 它正在处理我的代码

  • 10

    我遇到了同样的问题并尝试了很多方法来解决它,但是没有用 . 最后,我找到了我的方式 . 一些参考enter link description here

    希望我的代码可以帮助未来的人 . 我花了两天多的时间来解决它 . 以下是我的代码:

    //get current in useing excel
                Process[] excelProcsOld = Process.GetProcessesByName("EXCEL");
                Excel.Application myExcelApp = null;
                Excel.Workbooks excelWorkbookTemplate = null;
                Excel.Workbook excelWorkbook = null;
    try{
        //DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook
    }
    catch (Exception ex ){
    }
    finally
                {
                    //Compare the EXCEL ID and Kill it 
                    Process[] excelProcsNew = Process.GetProcessesByName("EXCEL");
                    foreach (Process procNew in excelProcsNew)
                    {
                        int exist = 0;
                        foreach (Process procOld in excelProcsOld)
                        {
                            if (procNew.Id == procOld.Id)
                            {
                                exist++;
                            }
                        }
                        if (exist == 0)
                        {
                            procNew.Kill();
                        }        
                    }
                }
    
  • 1

    您可以使用自己的 COM object excel pid杀死进程

    在dll导入代码下面添加一些地方

    [DllImport("user32.dll", SetLastError = true)]
    private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
    

    并使用

    if (excelApp != null)
                {
                    int excelProcessId = -1;
                    GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);
    
                    Process ExcelProc = Process.GetProcessById(excelProcessId);
                    if (ExcelProc != null)
                    {
                        ExcelProc.Kill();
                    }
                }
    
  • 0
    wb.Close();
             app.Quit();
    
             System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
             foreach (System.Diagnostics.Process p in process)
             {
                 if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now)
                 {
                     try
                     {
                         p.Kill();
                     }
                     catch { }
                 }
             }
    

    它关闭了名为“Excel”的最后10秒进程

  • 0

    关闭所有excel进程的正确方法

    var _excel = new Application();
    foreach (Workbook _workbook in _excel.Workbooks) {
        _workbook.Close(0);
    }
    
    _excel.Quit();
    _excel = null;
    var process = System.Diagnostics.Process.GetProcessesByName("Excel");
    foreach (var p in process) {
        if (!string.IsNullOrEmpty(p.ProcessName)) {
            try {
                p.Kill();
            } catch { }
        }
    }
    
  • 0

    基于另一种解决方案 . 我用过这个:

    IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd);
    excelObj.ActiveWorkbook.Close();
    
    System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
                    foreach (System.Diagnostics.Process p in process)
                    {
                        if (p.MainWindowHandle == xAsIntPtr)
                        {
                            try
                            {
                                p.Kill();
                            }
                            catch { }
                        }
                    }
    

    使用“MainWindowHandle”来识别进程并关闭他 .

    excelObj:这是我的Application Interop excel objecto

  • -1

    为每个Excel对象使用变量,并且必须循环 Marshal.ReleaseComObject >0 . 没有循环,Excel进程仍然保持活动状态 .

    public class test{
            private dynamic ExcelObject;
            protected dynamic ExcelBook;
            protected dynamic ExcelBooks;
            protected dynamic ExcelSheet;
    
    public void LoadExcel(string FileName)
            {
                Type t = Type.GetTypeFromProgID("Excel.Application");
                if (t == null) throw new Exception("Excel non installato");
                ExcelObject = System.Activator.CreateInstance(t);
                ExcelObject.Visible = false;
                ExcelObject.DisplayAlerts = false;
                ExcelObject.AskToUpdateLinks = false;
                ExcelBooks = ExcelObject.Workbooks;
                ExcelBook = ExcelBooks.Open(FileName,0,true);
                System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
                ExcelSheet = ExcelBook.Sheets[1];
            }
     private void ReleaseObj(object obj)
            {
                try
                {
                    int i = 0;
                 while(   System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0)
                    {
                        i++;
                        if (i > 1000) break;
                    }
                    obj = null;
                }
                catch 
                {
                    obj = null;
                }
                finally
                {
                    GC.Collect();
                }
            }
            public void ChiudiExcel() {
                System.Threading.Thread.CurrentThread.CurrentCulture = ci;
    
                ReleaseObj(ExcelSheet);
                try { ExcelBook.Close(); } catch { }
                try { ExcelBooks.Close(); } catch { }
                ReleaseObj(ExcelBooks);
                try { ExcelObject.Quit(); } catch { }
                ReleaseObj(ExcelObject);
            }
    }
    
  • 0

    我们可以使用以下代码关闭Excel应用程序,同时将xls转换为xlsx . 当我们执行这种任务然后Excel应用程序在任务管理器中运行时,我们应该关闭在后台运行的这个excel . Interop是一个Com组件,用于释放我们使用Marshal.FinalReleaseComObject的com组件 .

    private void button1_Click(object sender, EventArgs e)
        {
    
            Excel03to07("D:\\TestExls\\TestExcelApp.XLS");
    
        }
        private void Excel03to07(string fileName)
        {
            string svfileName = Path.ChangeExtension(fileName, ".xlsx");
            object oMissing = Type.Missing;
            var app = new Microsoft.Office.Interop.Excel.Application();
            var wb = app.Workbooks.Open(fileName, oMissing, oMissing,
                            oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
            wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
    
            wb.Close(false, Type.Missing, Type.Missing);
            app.Quit();
            GC.Collect();
            Marshal.FinalReleaseComObject(wb);
            Marshal.FinalReleaseComObject(app);
       }
    
  • 1

    大多数方法都有效,但excel过程始终保持到关闭应用程序 .

    当杀死excel进程一旦它不能再次在同一个线程中执行 - 不知道为什么 .

  • 1
    GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId);
            wb.Close(true,Missing.Value,Missing.Value);
            app.Quit();
            System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
            foreach (System.Diagnostics.Process p in process)
            {
                if (p.Id == iProcessId)
                {
                    try
                    {
                        p.Kill();
                    }
                    catch { }
                }
            }
    }
    [DllImport("user32.dll")]
    
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    
    uint iProcessId = 0;
    

    这个GetWindowThreadProcessId找到正确的进程ID o excell ....杀了它....享受它!

相关问题