We have a native C++ application which supports some VBA macros of various types over COM. One of these types, VBAExtension
, registers itself with the core C++ application, resulting in an instance of (a class derived from) IConnectionPointImpl<Extension, &DIID_IExtensionEvents, CComDynamicUnkArray>
. This works fine; both core and other VBA macros can access the methods on IExtensionEvents, given an appropriate VBAExtension object.
We also have a .NET assembly (written in C#) which is also loaded in to the core application at run-time. For historical reasons, the assembly is loaded in by an auto-running VBA macro; then, when the user presses a particular button, another VBA macro runs the main entry point of the assembly, which brings up a System.Windows.Forms
dialog for further interaction.
That’s the setup. I’m seeing some weird behaviour accessing the VBAExtension
methods from within the .NET assembly. Specifically, I am running the following code from various locations in the assembly:
foreach (VBAExtension ve in app.Extensions)
{
System.Diagnostics.Debug.Print("Ext: " + ve.Name);
}
If I run it from the constructor of the assembly’s main object; or from the assembly’s main entry point (before the dialog is displayed), everything is fine – I get the names of the VBAExtension
s printed out.
However, if I run the same code from a command kicked off by a button in the assembly’s (modal - we're calling form.ShowDialog()
) WinForm, the ve.Name
s are all blank. The pDispatch->Invoke
call made by the IConnectionPointImpl
subclass succeeds (returns S_OK), but does not set any return vars.
If I change the dialog to be non-modal (invoked with form.Show()
), then the names work again. The modality (modalness?) of the form appears to affect whether the IConnectionPointImpl
calls succeed.
Anyone know what's going on?
Edit: Since first posting, I've demonstrated that it's not the invoking call stack that matters; instead, it's whether the call is made from a modal dialog. I have updated the main text.
Edit 2: Per Hans Passant's answer, here are the answers to his diagnostic questions:
- As expected, in the good (modeless) case there is no error if I rename the VBA event handler. The call simply returns no data.
- I've put a MsgBox call into the VBA handler; it displays in the modeless case, but does not in the modal case. Ergo, the handler is not executed in the modal case.
- By use of
Err
, I can tell that if we hit an exception in the VBA handler we get a VBA error dialog. Once clearing that, the C++Invoke
call has 0x80020009 ("Exception occurred") as return code, and pExcepInfo filled in with generic failure values (VBA has swallowed the actual details) - The event does not fire on the second display of the modal dialog, either immediately following the first dialog or during a second invocation of the C# add-in.
I'll try to dig into our message loops as a next step.