Clearing CommandBar Buttons

I have a problem with my COM add-in, which lasted for several months, and I can’t understand why.

The implementation of IDTExtensibility2 has already been reviewed by Carlos Quintero (the guy behind MZ-Tools) and is considered correct.

In its recommendations, the OnBeginShutdown implementation sets the flag checked in OnDisconnection to ensure that ShutdownAddIn only works once (some VBE host applications do not call OnBeginShutdown , therefore):

 public void OnBeginShutdown(ref Array custom) { _isBeginShutdownExecuted = true; ShutdownAddIn(); } 

My add-in uses Ninject for DI / IoC, and my ShutdownAddIn method boils down to calling Dispose on an Ninject IKernel instance and then freeing all COM objects using Marshal.ReleaseComObject :

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

I can't think of an earlier time to run this code. However, when Dispose works on my command line and menu shells, I get an InvalidCastException in StopEvents when the command line / menu tries to StopEvents its controls:

 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 says that it cannot use for IConnectionPoint - and I found that the reason for this is that when this code works, my Target (wrapped __ComObject ) has already left, and I am left with an invalid pointer and a lingering reference to a COM object, which no longer exists.

If I catch all the exceptions that occurred during my stall process (I have more exceptions from the same root problem when I try Delete buttons and menus), the host application closes, but the host process remains, and then I should kill him from task manager. This behavior is consistent with a memory leak caused by a non-remote click handler, I think.


Is there a more reliable way to handle / delete event handlers for the Microsoft.Office.Core.CommandBarButton wrapper? Why are my wrapped COM objects already “gone” when OnBeginShutdown is OnBeginShutdown , if I haven't released them yet?

+7
c # ninject com com-interop vbide
source share
1 answer

I can be wrong, but I don’t think that InvalidCastException is because some COM object is gone, you will get a “COM object that was separated from its base RCW, in this case it cannot be used." InvalidCastException means that this means that the type cannot be converted to another type, and this can happen not only in the obvious case when the types of full names are different, but I also saw this in extreme cases, such as

1) The full type names are the same, but come from different assemblies or even from the same assembly, which somehow was downloaded twice from different places. Example: Case 1 mentioned in Isolating .NET Add-Ins for a VBA Editor Using COM Misses

2) The full type names are the same, but were loaded into different CLRs (2.0 / 4.0) in the same process. Example: A strange case is System.InvalidCastException ("Cannot pass a COM object of type 'System .__ ComObject for class type System.Windows.Forms.UserControl") showing a tool window

I would suggest getting the full type / assembly / CLR name for the types that were selected. Adding a temporary link to the Microsoft.VisualBasic link allows you to use Microsoft.VisualBasic.Information.TypeName (object) to get the actual type behind the __ComObject.

+5
source share

All Articles