[英]Problems calling IConnectionPointImpl interface from C++ invoked via modal WinForms
We have a native C++ application which supports some VBA macros of various types over COM. 我们有一个本机C ++应用程序,它通过COM支持一些各种类型的VBA宏。 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>
. 其中一种类型VBAExtension
向核心C ++应用程序注册,从而导致IConnectionPointImpl<Extension, &DIID_IExtensionEvents, CComDynamicUnkArray>
的实例(派生自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. 给定适当的VBAExtension对象,核心VBA和其他VBA宏都可以访问IExtensionEvents上的方法。
We also have a .NET assembly (written in C#) which is also loaded in to the core application at run-time. 我们还有一个.NET程序集(用C#编写),该程序集也在运行时加载到核心应用程序中。 For historical reasons, the assembly is loaded in by an auto-running VBA macro; 由于历史原因,程序集是通过自动运行的VBA宏加载的; 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. 然后,当用户按下特定按钮时,另一个VBA宏将运行程序集的主入口点,这将弹出System.Windows.Forms
对话框以进行进一步的交互。
That's the setup. 这就是设置。 I'm seeing some weird behaviour accessing the VBAExtension
methods from within the .NET assembly. 我看到从.NET程序VBAExtension
访问VBAExtension
方法有一些奇怪的行为。 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. 或从程序集的主入口点开始(显示对话框之前),一切都很好–我得到了打印出来的VBAExtension
的名称。
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. 但是,如果我从程序集的( 模态 -我们称为form.ShowDialog()
)WinForm中的按钮开始的命令中运行相同的代码,则ve.Name
都为空。 The pDispatch->Invoke
call made by the IConnectionPointImpl
subclass succeeds (returns S_OK), but does not set any return vars. 由IConnectionPointImpl
子类进行的pDispatch->Invoke
调用成功(返回S_OK),但未设置任何返回变量。
If I change the dialog to be non-modal (invoked with form.Show()
), then the names work again. 如果我将对话框更改为非模式对话框(由form.Show()
调用),则名称将再次起作用。 The modality (modalness?) of the form appears to affect whether the IConnectionPointImpl
calls succeed. 表单的形式(模态?)似乎会影响IConnectionPointImpl
调用是否成功。
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: 编辑2: Per Hans Passant的答案,以下是他的诊断性问题的答案:
Err
, I can tell that if we hit an exception in the VBA handler we get a VBA error dialog. 通过使用Err
,我可以告诉我们,如果我们在VBA处理程序中遇到异常,则会出现一个VBA错误对话框。 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) 清除该错误后,C ++ Invoke
调用将0x80020009(“发生异常”)作为返回代码,并用通用失败值填充了pExcepInfo(VBA吞噬了实际的详细信息) I'll try to dig into our message loops as a next step. 下一步,我将尝试深入探讨我们的消息循环。
There are excessively few hard facts in this question to build an answer on. 这个问题上几乎没有什么硬道理可以作为答案。 Could be something very simple, could be a nasty memory corruption problem or an obscure dependency inside the VBA interpreter on the thread state. 可能很简单,可能是令人讨厌的内存损坏问题,也可能是VBA解释器内部对线程状态的模糊依赖。 The rough diagnostic is that the VBA event handler simply did not run. 粗略的诊断是VBA事件处理程序根本没有运行。 That is not an uncommon accident in general, the declarative style used in Basic to declare event handlers leave very few good way to ever diagnose subscription problems. 一般而言,这并不是罕见的事故,Basic中用于声明事件处理程序的声明式样式几乎没有诊断订阅问题的好方法。 Many a VBA programmer has lost clumps of hair trying to troubleshoot a "why did the event handler not run" problem like this one. 许多VBA程序员在解决此类“为什么事件处理程序为什么不运行”的问题时,一头雾水。
Gather some hard facts first and add them to your question: 首先收集一些困难的事实,并将其添加到您的问题中:
Focusing a bit on ShowDialog(). 将重点放在ShowDialog()上。 This method does have plenty of side-effects. 这种方法确实有很多副作用。 The first thing that no longer works is the message loop in your C++ code. 不再起作用的第一件事是C ++代码中的消息循环。 It is now the .NET message loop that dispatches messages. 现在是.NET消息循环分发消息。 Look at yours for side-effects, doing more work than simply GetMessage/DispatchMessage(). 看看您的副作用,除了简单地执行GetMessage / DispatchMessage()之外,还要做更多的工作。 That work no longer gets done. 这项工作不再完成。 Also search your codebase for PostThreadMessage(), those messages fall on the floor when the .NET code pumps. 还要在您的代码库中搜索PostThreadMessage(),当.NET代码启动时,这些消息就会掉在地上。
And keep in mind that your native C++ code loses control when the C# code calls ShowDialog(). 并且请记住,当C#代码调用ShowDialog()时,您的本机C ++代码将失去控制。 It doesn't regain control until you close the window. 关闭窗口后,它才能重新获得控制权。 That can trigger a simple order-of-execution problem, your C++ code should not do anything important after does whatever it does to get the C# code running. 这可能会触发一个简单的执行顺序问题,即在使C#代码运行之后,您的C ++代码不应做任何重要的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.