清理CommandBar按钮

时间:2016-11-30 19:47:00

标签: 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();
}

我的加载项使用Ninject进行DI / IoC,我的ShutdownAddIn方法归结为在Ninject Dispose实例上调用IKernel,然后使用{{释放所有COM对象1}}:

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)已经消失,我留下了一个无效的指针和一个不再存在的COM对象的延迟引用。

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

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

1 个答案:

答案 0 :(得分:5)

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

1)类型全名是相同的,但来自不同的程序集,甚至来自同一个程序集,不知何故从不同的位置加载了两次。示例:Isolating .NET-based add-ins for the VBA editor with COM Shims

中提到的案例1

2)类型全名相同,但在同一过程中已加载到不同的CLR(2.0 / 4.0)中。示例:The strange case of System.InvalidCastException (“Unable to cast COM object of type ‘System.__ComObject’ to class type System.Windows.Forms.UserControl”) showing toolwindow

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