我的 COM 加载项有一个问题,拖了几个月,我不知道为什么。
该IDTExtensibility2
实现已经由 Carlos Quintero(MZ-Tools 背后的人)进行了同行评审,并被认为是正确的。
根据他的建议,OnBeginShutdown
实现设置了一个已签入的标志OnDisconnection
,以确保ShutdownAddIn
只运行一次(某些 VBE 主机应用程序不调用OnBeginShutdown
,这就是原因):
public void OnBeginShutdown(ref Array custom)
{
_isBeginShutdownExecuted = true;
ShutdownAddIn();
}
我的插件使用 Ninject 进行 DI/IoC,我的ShutdownAddIn
方法归结为调用Dispose
NinjectIKernel
实例,然后释放所有 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 对象在运行时已经“消失”了?