我的COM加载项已经拖了好几个月了,我找不到原因。清理CommandBar按钮
IDTExtensibility2
的实现已经由Carlos Quintero(MZ-Tools背后的人)进行了同行评审,并被认为是正确的。
按他的建议OnBeginShutdown
实现设置是在OnDisconnection
检查,以确保ShutdownAddIn
只运行一次一个标志(有些VBE主机应用程序不叫OnBeginShutdown
,这就是为什么):
public void OnBeginShutdown(ref Array custom)
{
_isBeginShutdownExecuted = true;
ShutdownAddIn();
}
我的外接使用Ninject的DI/IoC的,而我的ShutdownAddIn
方法归结为对Ninject IKernel
实例调用Dispose
,然后释放所有的COM对象与Marshal.ReleaseComObject
:
private void ShutdownAddIn()
{
if (_kernel != null)
{
_kernel.Dispose();
_kernel = null;
}
_ide.Release();
_isInitialized = false;
}
我想不到早些时候运行这段代码。然而,当Dispose
我的命令栏和菜单包装奔跑,我得到一个InvalidCastException
在StopEvents
我当命令栏/菜单尝试拆卸他们的控件:
public void HandleEvents()
{
// register the unmanaged click events
((Microsoft.Office.Core.CommandBarButton)Target).Click += Target_Click;
}
public void StopEvents()
{
// unregister the unmanaged click events
((Microsoft.Office.Core.CommandBarButton)Target).Click -= Target_Click;
}
public event EventHandler<CommandBarButtonClickEventArgs> Click;
private void Target_Click(Microsoft.Office.Core.CommandBarButton ctrl, ref bool cancelDefault)
{
// handle the unmanaged click events and fire a managed event for managed code to handle
var handler = Click;
if (handler == null)
{
return;
}
var args = new CommandBarButtonClickEventArgs(new CommandBarButton(ctrl));
handler.Invoke(this, args);
cancelDefault = args.Cancel;
}
的InvalidCastException
说,它无法投射到IConnectionPoint
- 而我发现的原因是因为当这段代码运行时,我的Target
(包装的__ComObject
)已经不存在了,我剩下一个无效的指针和一个COM对象的引用存在。
那我要是追到期间我拆机过程中引发的所有异常(我有更多的例外是同根的问题而产生,当我尝试Delete
的按钮和菜单),主机应用程序关闭,但主机进程依然 - 然后我必须从任务管理器中杀死它。这种行为与我认为未删除的点击处理程序导致的内存泄漏一致。
有一个更强大的方式,我可以处理添加/一Microsoft.Office.Core.CommandBarButton
包装删除事件处理程序?如果我还没有发布它们,为什么当OnBeginShutdown
运行时,我的包装COM对象已经“消失”了?
从不同位置加载的程序集......可能'Rubberduck.VBEditor.dll'被搞砸了......边缘案例1似乎是一个真正的可能性。 –
这听起来很奇怪,但这可能源于我们使用微软的互操作PIA库而不是生成我们自己的@Mat'sMug?在黑暗中拍摄。 https://www.mztools.com/articles/2012/MZ2012011.aspx – RubberDuck
昨晚我没有看到它,但现在我看到,在调用handler.Invoke后,你不是在ctrl上调用Marshal.ReleaseComObject .NET-您在Target_Click事件处理程序中从COM端接收到的RCW。这是一个泄漏。或者,如果将CommandBarButton包装器作为参数接收,它会在Dispose方法中调用它,您应该在事件处理程序中调用其Dispose方法,而不是在下一次垃圾回收之前将其保留为浮动状态。 –