[英]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
表示它無法InvalidCastException
為IConnectionPoint
- 而我發現的原因是因為當這段代碼運行時,我的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.