[英]Problems calling IConnectionPointImpl interface from C++ invoked via modal WinForms
我们有一个本机C ++应用程序,它通过COM支持一些各种类型的VBA宏。 其中一种类型VBAExtension
向核心C ++应用程序注册,从而导致IConnectionPointImpl<Extension, &DIID_IExtensionEvents, CComDynamicUnkArray>
的实例(派生自IConnectionPointImpl<Extension, &DIID_IExtensionEvents, CComDynamicUnkArray>
。 这很好用; 给定适当的VBAExtension对象,核心VBA和其他VBA宏都可以访问IExtensionEvents上的方法。
我们还有一个.NET程序集(用C#编写),该程序集也在运行时加载到核心应用程序中。 由于历史原因,程序集是通过自动运行的VBA宏加载的; 然后,当用户按下特定按钮时,另一个VBA宏将运行程序集的主入口点,这将弹出System.Windows.Forms
对话框以进行进一步的交互。
这就是设置。 我看到从.NET程序VBAExtension
访问VBAExtension
方法有一些奇怪的行为。 具体来说,我正在程序集中的不同位置运行以下代码:
foreach (VBAExtension ve in app.Extensions)
{
System.Diagnostics.Debug.Print("Ext: " + ve.Name);
}
如果我从程序集主对象的构造函数运行它; 或从程序集的主入口点开始(显示对话框之前),一切都很好–我得到了打印出来的VBAExtension
的名称。
但是,如果我从程序集的( 模态 -我们称为form.ShowDialog()
)WinForm中的按钮开始的命令中运行相同的代码,则ve.Name
都为空。 由IConnectionPointImpl
子类进行的pDispatch->Invoke
调用成功(返回S_OK),但未设置任何返回变量。
如果我将对话框更改为非模式对话框(由form.Show()
调用),则名称将再次起作用。 表单的形式(模态?)似乎会影响IConnectionPointImpl
调用是否成功。
有人知道发生了什么吗?
编辑:自从第一次发布以来,我已经证明,重要的不是调用调用堆栈; 而是通过模态对话框进行调用。 我已经更新了正文。
编辑2: Per Hans Passant的答案,以下是他的诊断性问题的答案:
Err
,我可以告诉我们,如果我们在VBA处理程序中遇到异常,则会出现一个VBA错误对话框。 清除该错误后,C ++ Invoke
调用将0x80020009(“发生异常”)作为返回代码,并用通用失败值填充了pExcepInfo(VBA吞噬了实际的详细信息) 下一步,我将尝试深入探讨我们的消息循环。
这个问题上几乎没有什么硬道理可以作为答案。 可能很简单,可能是令人讨厌的内存损坏问题,也可能是VBA解释器内部对线程状态的模糊依赖。 粗略的诊断是VBA事件处理程序根本没有运行。 一般而言,这并不是罕见的事故,Basic中用于声明事件处理程序的声明式样式几乎没有诊断订阅问题的好方法。 许多VBA程序员在解决此类“为什么事件处理程序为什么不运行”的问题时,一头雾水。
首先收集一些困难的事实,并将其添加到您的问题中:
将重点放在ShowDialog()上。 这种方法确实有很多副作用。 不再起作用的第一件事是C ++代码中的消息循环。 现在是.NET消息循环分发消息。 看看您的副作用,除了简单地执行GetMessage / DispatchMessage()之外,还要做更多的工作。 这项工作不再完成。 还要在您的代码库中搜索PostThreadMessage(),当.NET代码启动时,这些消息就会掉在地上。
并且请记住,当C#代码调用ShowDialog()时,您的本机C ++代码将失去控制。 关闭窗口后,它才能重新获得控制权。 这可能会触发一个简单的执行顺序问题,即在使C#代码运行之后,您的C ++代码不应做任何重要的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.