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?