簡體   English   中英

清理CommandBar按鈕

[英]Cleaning up CommandBar buttons

我有一個問題,我的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 IKernel實例上調用Dispose ,然后使用Marshal.ReleaseComObject釋放所有COM對象:

private void ShutdownAddIn()
{
    if (_kernel != null)
    {
        _kernel.Dispose();
        _kernel = null;
    }
    _ide.Release();
    _isInitialized = false;
}

我想不出更早的時間來運行這段代碼。 然而,當Dispose在我的命令欄和菜單包裝器上運行時,當命令欄/菜單嘗試拆除它們的控件時,我在StopEvents收到InvalidCastException

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表示它無法InvalidCastExceptionIConnectionPoint - 而我發現的原因是因為當這段代碼運行時,我的Target (包裝的__ComObject )已經消失了,我留下了一個無效的指針和對不再存在的COM對象的延遲引用。

如果我抓住了在我的拆解過程中拋出的所有異常(我有更多例外源於相同的根問題,當我嘗試Delete按鈕和菜單時),主機應用程序關閉但主機進程仍然存在 - 然后我必須將其終止來自任務管理器 此行為與我認為未刪除的點擊處理程序導致的內存泄漏一致。


有沒有更強大的方法可以處理為Microsoft.Office.Core.CommandBarButton包裝器添加/刪除事件處理程序? OnBeginShutdown運行時,為什么我的包裝COM對象已經“消失”,如果我還沒有發布它們?

我可能是錯的,但我不認為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背后的實際類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM