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

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

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

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


当前回答

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

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

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

其他回答

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

你不能这样做:

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

你必须这样做

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

随后释放物体。

我有一个想法,尝试关闭你打开的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=空;}}

在我的VSTO插件中新建应用程序对象后,我在关闭PowerPoint时遇到了同样的问题。我在这里尝试了所有的答案,但收效甚微。

这是我为我的案例找到的解决方案-不要使用“新应用程序”,ThisAddIn的AddInBase基类已经有了“应用程序”的句柄。如果你在需要的地方使用这个手柄(如果必须的话,让它保持静态),那么你不必担心清理它,PowerPoint也不会挂在近处。

当上面的所有内容都不起作用时,请尝试给Excel一些时间来关闭工作表:

app.workbooks.Close();
Thread.Sleep(500); // adjust, for me it works at around 300+
app.Quit();

...
FinalReleaseComObject(app);

拍摄Excel程序并咀嚼泡泡糖

public class MyExcelInteropClass
{
    Excel.Application xlApp;
    Excel.Workbook xlBook;

    public void dothingswithExcel() 
    {
        try { /* Do stuff manipulating cells sheets and workbooks ... */ }
        catch {}
        finally {KillExcelProcess(xlApp);}
    }

    static void KillExcelProcess(Excel.Application xlApp)
    {
        if (xlApp != null)
        {
            int excelProcessId = 0;
            GetWindowThreadProcessId(xlApp.Hwnd, out excelProcessId);
            Process p = Process.GetProcessById(excelProcessId);
            p.Kill();
            xlApp = null;
        }
    }

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