Visio VSTO 和 Page.GetFormulas 方法并确保在关机时清理所有 COM 对象

Visio VSTO & the Page.GetFormulas method and making sure all COM objects are cleaned up on shutdown

对于业余开发人员来说,Whosebug 上关于如何确保在 运行 Office VSTO 加载项后正确清理 COM 对象的大量建议和讨论令人困惑,说得客气一点。建议无处不在,从“不要做任何事情”这将为您完成,到明确开始垃圾收集(一次,或者不是万无一失,需要做两次),到使用 Marshal.ReleaseComObject 自己清理所有 COM 对象(这需要您跟踪您使用的所有 COM 对象)。

一些拥有多年 Office 加载项开发经验的专家坚持认为,自己清理 COM 对象是获得稳定、可预测的代码行为的方法: https://www.add-in-express.com/creating-addins-blog/2020/07/20/releasing-com-objects-garbage-collector-marshal-relseasecomobject/

所以我决定走安全路线,在我自己用完 COM 对象后立即清理它们,必须做出继续前进的决定。

我对 Visio 的问题是,为了加快代码的速度,Visio 有几个函数可以让我们一次从多个 Visio 形状读取数据,例如 Page.GetFormulas。像这样一次从数百个 Visio 形状读取数据的性能明显优于一次从一个形状读取数据。通过互操作一次而不是数百次对性能有好处。

我想知道如果我之后需要清理所有 COM 对象这是否有效,因为我知道从形状读取数据涉及 Visio Cell 对象,现在隐式 used/referenced。

当我调用 Page.GetResults 和 Page.DropMany 等批量函数时发生了什么 'under the hood' 如果我无法清理所有生成的 COM 对象,这是否会导致不稳定我自己。

感谢您分享您的见解,对于像我这样的业余开发人员来说,这是一个非常令人困惑的话题。

如果您想确保每个 Visio COM 对象在退出前都已死,您可以尝试这个(例如,在卸载时,即在 ThisAddIn_Shutdown 中,两次以确保所有代都被杀死)。

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

假设您没有任何 global 对 COM 对象的引用,如果您首先清除它们(分配 null 就足够了,如果您在那之后调用 GC)。请注意,此操作相对 较慢 ,因此如果您关心性能,经常调用该段代码可能不是一个好主意。

不过,让 COM 对象保持活动状态(作为“僵尸”)应该不是问题,除非您有特定的问题为什么要明确清除 COM 引用。如果那些“僵尸”类似于形状对象,那么保留它们基本上只会浪费内存或产生死引用,除非您关心内存消耗或尝试使用死对象,否则这应该不是问题。关闭应用程序应该会杀死它们。