c# - 如何在.NET中处理COM对象的事件时释放所有COM对象

标签 c# excel memory-management com

我正在 C# 中使用 COM Excel 应用程序类。我处理了 WorkbookBeforeClose。但现在我无法正确释放COM对象。

请注意,我在处理此事件之前成功地正确释放了 COM 对象,并且在注释该部分代码时,我的应用程序可以正常工作。

哪些 COM 对象没有从内存中释放以及如何正确释放它?

编辑: 我做了什么:

public void Init()
{
   ...
   application = new Excel.Application();
   application.WorkbookBeforeClose += new Excel.AppEvents_WorkbookBeforeCloseEventHandler(application_WorkbookBeforeClose);
}
...
void application_WorkbookBeforeClose(Excel.Workbook Wb, ref bool Cancel)
    {
        if (WorkbookBeforeClose != null)
        {
            ExcelCloseEventArgs args = new ExcelCloseEventArgs();
            WorkbookBeforeClose(this, args);
            Cancel = args.Cancel;
        }
        else
            Cancel = false;
    }
...
private void closeExcel()
    {
        try
        {
            if (workbook != null)
            {
                workbook.Close(false);
            }
        }
        catch (Exception e) { }
        finally
        {
            if (workbooks != null)
                Marshal.ReleaseComObject(workbooks);
            if (workbook != null)
                Marshal.ReleaseComObject(workbook);
        }

        try
        {
            if (application != null)
            {
                application.WorkbookBeforeClose -= handler;
                application.Quit();
                Marshal.ReleaseComObject(application);
                Marshal.ReleaseComObject(handler);
                process.WaitForExit();
            }
        }
        catch (Exception e) { throw; }
        finally
        {

        }

        workbook = null;
        workbooks = null;
        application = null;
        if (process != null && !process.HasExited)
            process.Kill();
        if (threadCulture != null)
            Thread.CurrentThread.CurrentCulture = threadCulture;
        initialized = false;
    }

应用程序暂停process.WaitForExit()

最佳答案

.NET 中的内存管理是自动的。自己显式调用 Marshal.ReleaseComObject() 是一个错误。不仅因为太早这样做很容易使 RCW 崩溃,而且特别是因为引用计数通常是隐藏的。索引器和事件是棘手的。缺少一个 ReleaseComObject 调用就足以使其回退到垃圾收集器来处理它。 GC 需要一些时间来释放内存(和引用计数),这是一个特性,而不是一个错误。

如果您真的非常希望 COM 服务器按需退出,而不是让垃圾收集器来处理它,那么请将您拥有的所有引用设置为 null,取消订阅事件处理程序并调用 GC.Collect()。不需要 ReleaseComObject 调用。检查this blog post寻求专业人士的见解。

关于c# - 如何在.NET中处理COM对象的事件时释放所有COM对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6597016/

相关文章:

c# - 从 C++ 启动 C# .Net 应用程序

c# - 如何在 C# 中弹出 url 段?

excel - Power Query 加载到数据透视表与添加到 Power Pivot 模型

c - C中字符串的内存分配将在哪里进行

python - C 扩展中的函数随机停止 python 程序执行

c# - 在 C# 中处理 DBNull

c# - 使用一个类来更新数据?

javascript - 使用 Node 解析 XLSX 并创建 json

java - 动态添加外部(跨工作簿)引用

python - 利用 "Copy-on-Write"将数据复制到 Multiprocessing.Pool() 工作进程