清理CommandBar按钮

Mat*_*don 7 c# com ninject com-interop vbide

我有一个问题,我的COM加载项拖了几个月,我无法弄清楚为什么.

IDTExtensibility2实施已经由Carlos Quintero(MZ-Tools背后的人)进行了同行评审,并且被认为是正确的.

根据他的建议,OnBeginShutdown实现设置了一个签入的标志OnDisconnection,以确保ShutdownAddIn只运行一次(某些VBE主机应用程序不调用OnBeginShutdown,这就是原因):

public void OnBeginShutdown(ref Array custom)
{
    _isBeginShutdownExecuted = true;
    ShutdownAddIn();
}
Run Code Online (Sandbox Code Playgroud)

我的插件使用Ninject进行DI/IoC,我的ShutdownAddIn方法归结为调用DisposeNinject IKernel实例,然后释放所有COM对象Marshal.ReleaseComObject:

private void ShutdownAddIn()
{
    if (_kernel != null)
    {
        _kernel.Dispose();
        _kernel = null;
    }
    _ide.Release();
    _isInitialized = false;
}
Run Code Online (Sandbox Code Playgroud)

我想不出更早的时间来运行这段代码.然而,当Dispose我的命令栏和菜单包装奔跑,我发现了一个InvalidCastExceptionStopEvents当命令栏/菜单尝试拆卸他们的控制:

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;
}
Run Code Online (Sandbox Code Playgroud)

InvalidCastException说,它无法投射到IConnectionPoint-和我所发现的是,这样做的原因是因为此代码运行时,我的Target(包裹__ComObject)已经走了,我留下了一个无效的指针和缠绵引用不再存在的COM对象.

如果我抓住了在我的拆解过程中抛出的所有异常(我有更多例外源于相同的根问题,当我尝试Delete按钮和菜单时),主机应用程序关闭但主机进程仍然存在 - 然后我必须从任务经理.此行为与我认为未删除的点击处理程序导致的内存泄漏一致.


有没有更强大的方法可以处理为Microsoft.Office.Core.CommandBarButton包装器添加/删除事件处理程序?OnBeginShutdown如果我还没有发布它们,为什么我的包装COM对象在运行时已经"消失" 了?

Car*_*ero 5

我可能是错的,但我不认为InvalidCastException是因为某些COM对象消失了,在这种情况下你会收到"与其底层RCW分离的COM对象".InvalidCastException意味着它意味着一个类型不能转换为另一种类型,并且这种情况不仅发生在类型全名不同的明显情况下,而且我在边缘情况下也看到了它,例如

1)类型全名是相同的,但来自不同的程序集,甚至来自同一个程序集,不知何故从不同的位置加载了两次.示例:使用COM Shims为VBA编辑器隔离基于.NET的加载项中提到的案例1

2)类型全名相同,但在同一过程中已加载到不同的CLR(2.0/4.0)中.示例:System.InvalidCastException的奇怪情况("无法将类型为'System .__ ComObject'的COM对象强制转换为类类型System.Windows.Forms.UserControl"),显示工具窗口

我建议获取所投射类型的完整类型名称/程序集名称/ CLR.添加对Microsoft.VisualBasic引用的临时引用允许您使用Microsoft.VisualBasic.Information.TypeName(object)来获取__ComObject背后的实际类型.