首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >清理CommandBar按钮

清理CommandBar按钮
EN

Stack Overflow用户
提问于 2016-11-30 19:47:00
回答 1查看 187关注 0票数 7

我有一个问题,我的COM插件已经拖了几个月,我不知道为什么。

IDTExtensibility2实现已经被Carlos (MZ-Tools背后的家伙)同行评审过,并且被认为是正确的。

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

代码语言:javascript
复制
public void OnBeginShutdown(ref Array custom)
{
    _isBeginShutdownExecuted = true;
    ShutdownAddIn();
}

我的外接程序将Ninject用于DI/IoC,而我的ShutdownAddIn方法可以归结为调用Ninject IKernel实例上的Dispose,然后用Marshal.ReleaseComObject释放所有COM对象。

代码语言:javascript
复制
private void ShutdownAddIn()
{
    if (_kernel != null)
    {
        _kernel.Dispose();
        _kernel = null;
    }
    _ide.Release();
    _isInitialized = false;
}

我想不出更早运行这段代码的时间了。然而,当Dispose在我的命令栏和菜单包装程序上运行时,当命令栏/菜单试图拆除它们的控件时,我在StopEvents中得到了一个InvalidCastException

代码语言:javascript
复制
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按钮和菜单时,有更多的来自同一根问题的异常),主机应用程序将关闭,但是主机进程仍然存在--然后我必须从Task中杀死它。这种行为与未删除的单击处理程序造成的内存泄漏是一致的。

是否有更健壮的方法来处理为Microsoft.Office.Core.CommandBarButton包装器添加/删除事件处理程序的问题?如果我还没有发布OnBeginShutdown,为什么我的包装COM对象在运行时已经“消失”了呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-11-30 22:06:13

我可能错了,但我不认为InvalidCastException是因为一些COM对象消失了,在这种情况下,您将收到“已与其底层RCW分离的COM对象”。InvalidCastException的意思是,一种类型不能转换为另一种类型,这种情况不仅在类型全名不同的明显情况下发生,而且我在边缘情况下也看到过,例如

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

2)类型全名相同,但在同一进程中加载在不同的CLR (2.0 / 4.0)中。示例:ComObject‘to class type System.Windows.Forms.UserControl“)显示工具窗口

我建议获取正在转换的类型的完整类型名称/程序集名称/CLR。向Microsoft.VisualBasic.Information.TypeName(object)引用添加临时引用允许您使用Microsoft.VisualBasic获取__ComObject后面的实际类型。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40896893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档