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


86

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

在此处输入图片说明

我使用以下代码打开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中看到类似的问题(例如thisthis),并测试了答案,但这是行不通的。


Excel和Word的运行速度慢,并且伴随着您遇到的许多怪癖。这些文件是zip文件,其中包含一些XML和其他内容。还有可以打开文档的Open XML SDK(或更新的版本)。这样的代码也可以在没有本地安装Office的情况下工作。考虑不使用Excel
Sten Petrov

Answers:


94

试试这个:

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

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

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)或者,如果您要进行后期绑定,使用零有时会更容易。 Workbook.Close(0) 这就是我在自动关闭工作簿时所做的方式。

我也去查找了它的文档,并在这里找到了它: Excel Workbook关闭

谢谢,


谢谢亲爱的迈克尔,它的工作正常:excelBook.Close(0)
Javad Yousefi

嗨,大家好,当您打开一个Excel文件进​​行阅读时,这不起作用。以下是代码var excelApp = new Application(); var workBooks = excelApp.Workbooks.Open @“ c:\ temp \ myexcel.xlsx”); workBooks.Close(0); excelApp.Quit();
user1131926

我已经使用了applicationClass ...,并且我使用了上面的代码来
放置

3
在对所有这些答案进行多次尝试失败之后,我采用了该解决方案来获取我打开的进程ID并直接将其杀死。
UndeadBob

@Singaravelan:您检查过David Clarke的答案了吗?
对映阮

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

试试这个..它对我有用...您应该释放该xl应用程序对象以停止该过程。


14

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

避免使用双点调用表达式,例如:

var workbook = excel.Workbooks.Open(/*params*/)

...因为以这种方式,您不仅为工作簿创建了RCW对象,而且为工作簿创建了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);

我将其包装在a中,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);
}

2
这对我有用,将工作簿分配给变量,以便可以将其清除。还有一项观察,我在清除Web应用程序和控制台应用程序中的excel应用程序时使用了完全相同的代码。删除双点更新之前的代码在控制台应用程序中可以正常工作,但是在Web应用程序中运行时,它不会清除EXCEL.EXE。我不确定为什么他们的行为有所不同,但是摆脱了双点引用,在Web应用程序中将其修复。
IronHide 2015年

为我工作。我认为要释放comobject,必须释放所有相关对象。我对solidworks程序有同样的问题。
Gs。

1
关闭工作簿,退出Excel应用程序,避免双点调用,并释放创建的每个COM对象。那对我有用。救生答案。谢谢。
思南ILYAS

13

想到这一点,它杀死了进程:

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

感谢您的回答。您的第一个解决方案将关闭所有打开的Excel文件。当我使用'excelBook.Close'时,会出现excel保存对话框,但我不想要它:(
Javad Yousefi

1
我对其进行了编辑,并在其中添加了一行代码,以便在代码中执行saveAs,该代码将用代码替换对话框,希望对您有所帮助。:)
Morris Miao

1
我只是将其用于对打开的Excel进程的初始检查,并将ID保存在列表中。然后进行新的Excel流程,进行必要的编辑,并关闭ID列表中未包含的所有Excel流程。
182764125216 2014年

这不是从任务管理器释放excel的正确方法。您应该释放所有创建的对象,包括那些在后台创建的对象,例如WorkBOoks。
ehh 2016年

这样,您将杀死每个正在运行的Excel进程。问题是,可能有其他用户或应用程序同时使用Excel。请记住,如果您愿意这样做。
思南ILYAS

5

杀死Excel并不总是那么容易。请参阅本文:杀死Excel的50种方法

本文就如何使Excel正常退出获得了Microsoft的最佳建议(MS Knowlege基础文章),但是如果有必要,还可以通过终止进程来确保做到这一点。我喜欢再降落伞。

确保关闭所有打开的工作簿,退出应用程序并释放xlApp对象。最后检查该进程是否仍然存在,如果是,则将其终止。

本文还确保了我们不会杀死所有Excel进程,而只会杀死已启动的确切进程。

另请参阅从窗口句柄获取流程

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

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

这是唯一对我有用的解决方案。谢谢。
乔恩·沃特

2

我遇到了同样的问题,并尝试了许多方法来解决它,但是没有用。最后,我通过自己的方式找到了。一些参考在这里输入链接描述

希望我的代码可以对将来的人有所帮助。我已经花了两天多的时间来解决它。以下是我的代码:

//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

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


是的,但是当我使用它时,会出现“保存”对话框,但我不希望它出现:(
Javad Yousefi 2013年

1

您可以使用自己的COM对象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();
                }
            }

1

我发现Marshal.ReleaseComObjectWhile循环中完成垃圾回收很重要。

static void Main(string[] args)
{
    Excel.Application xApp = new Excel.Application();
    Excel.Workbooks xWbs = xApp.Workbooks;
    Excel.Workbook xWb = xWbs.Open("file.xlsx");

    Console.WriteLine(xWb.Sheets.Count);

    xWb.Close();
    xApp.Quit();

    while (Marshal.ReleaseComObject(xWb) != 0);
    while (Marshal.ReleaseComObject(xWbs) != 0);
    while (Marshal.ReleaseComObject(xApp) != 0);

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

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对象


0

为每个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

通过使用以下代码,我们可以在将xls转换为xlsx时关闭Excel应用程序。当我们执行此类任务时,Excel应用程序正在任务管理器中运行,我们应关闭在后台运行的Excel。Interop是一个Com组件,为了释放com组件,我们使用了Marshal.FinalReleaseComObject。

 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);
   }

0

大多数方法都可以使用,但是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…。杀死它之后……享受它!


-1
private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Unable to release the Object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

尽管这段代码可以解决问题,但 包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加解释,并指出适用的限制和假设。
戴夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.