我在C#(ApplicationClass)中使用Excel互操作,并在finally子句中放置了以下代码:

while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();

尽管这种方法有效,但即使在我关闭Excel之后,Excel.exe进程仍处于后台。它只在我的应用程序被手动关闭后发布。

我做错了什么,或者是否有其他方法可以确保正确处理互操作对象?


当前回答

普通开发人员,你的解决方案都不适合我,所以我决定实施一个新的技巧。

首先,让我们指定“我们的目标是什么?”=>“在任务管理器中完成任务后不要看到excel对象”

好的。让no挑战并开始销毁它,但考虑不要销毁并行运行的其他Excel实例。

因此,获取当前处理器的列表并获取EXCEL进程的PID,然后一旦完成任务,我们将在进程列表中创建一个具有唯一PID的新访客,找到并销毁该访客。

<请记住,在excel工作过程中,任何新的excel流程都将被检测为新的并被销毁><更好的解决方案是捕获新创建的excel对象的PID并销毁它>

Process[] prs = Process.GetProcesses();
List<int> excelPID = new List<int>();
foreach (Process p in prs)
   if (p.ProcessName == "EXCEL")
       excelPID.Add(p.Id);

.... // your job 

prs = Process.GetProcesses();
foreach (Process p in prs)
   if (p.ProcessName == "EXCEL" && !excelPID.Contains(p.Id))
       p.Kill();

这解决了我的问题,也希望你的问题。

其他回答

我有一个想法,尝试关闭你打开的excel进程:

在打开exclapplication之前,获取名为oldProcessIds的所有进程ID。打开重叠部分。现在获取名为nowProcessIds的所有超应用进程ID。当需要退出时,杀死oldProcessIds和nowProcessIds之间的except id。私有静态Excel.Application GetExcelApp(){如果(_excelApp==空){var processIds=System.Diagnostics.Process.GetProcessesByName(“EXCEL”).Select(a=>a.Id).ToList();_excelApp=新建Excel.Application();_excelApp.DisplayAlerts=false;_excelApp.Visible=false;_excelApp.ScreenUpdate=false;var newProcessIds=System.Diagnostics.Process.GetProcessesByName(“EXCEL”).Select(a=>a.Id).ToList();_excelApplicationProcessId=newProcessIds.Except(processIds).FirstOrDefault();}return _excelApp;}公共静态void Dispose(){尝试{_excelApp.Workbooks.Close();_excelApp.Quit();System.Runtime.InteropServices.Marsal.ReleaseComObject(_excelApp);_excelApp=空;GC.Collect();GC.WaitForPendingFinalizers();if(_excelApplicationProcessId!=默认值(int)){var process=System.Diagnostics.process.GetProcessById(_excelApplicationProcessId);过程Kill();_excelApplicationProcessId=默认值(int);}}catch(异常ex){_excelApp=空;}}

您需要意识到Excel对您正在运行的文化也非常敏感。

您可能会发现,在调用Excel函数之前,需要将区域性设置为EN-US。这并不适用于所有函数,但适用于其中一些函数。

    CultureInfo en_US = new System.Globalization.CultureInfo("en-US"); 
    System.Threading.Thread.CurrentThread.CurrentCulture = en_US;
    string filePathLocal = _applicationObject.ActiveWorkbook.Path;
    System.Threading.Thread.CurrentThread.CurrentCulture = orgCulture;

即使您正在使用VSTO,这也适用。

有关详细信息:http://support.microsoft.com/default.aspx?scid=kb;我们;第320369季度

Excel命名空间中的任何内容都需要发布。时期

你不能这样做:

Worksheet ws = excel.WorkBooks[1].WorkSheets[1];

你必须这样做

Workbooks books = excel.WorkBooks;
Workbook book = books[1];
Sheets sheets = book.WorkSheets;
Worksheet ws = sheets[1];

随后释放物体。

我一直遵循VVS答案中的建议。然而,为了使这个答案与最新的选项保持同步,我认为我未来的所有项目都将使用“NetOffice”库。

NetOffice是Office PIA的完全替代品,完全不受版本限制。它是一个托管COM包装器的集合,可以处理在.NET中使用Microsoft Office时经常引起此类麻烦的清理。

一些关键功能包括:

大部分与版本无关(记录了与版本相关的功能)无相关性无PIA没有注册无VSTO

我与该项目毫无关联;我真的很欣赏头痛的明显减轻。

Excel并非设计为通过C++或C#编程。COM API专门设计用于Visual Basic、VB.NET和VBA。

此外,此页上的所有代码示例都不是最佳的,原因很简单,即每个调用都必须跨越托管/非托管边界,并且还忽略了这样一个事实,即Excel COM API可以自由地使任何调用失败,并带有一个神秘的HRESULT,表示RPC服务器正忙。

我认为自动化Excel的最佳方法是将数据收集到尽可能大的数组中,并将其发送到VBA函数或子函数(通过Application.Run),然后执行任何所需的处理。此外,在调用Application.Run时,请确保注意excel正忙的异常,然后重试调用Application.Run。