gpt4 book ai didi

c# - 从通过模态 WinForms 调用的 C++ 调用 IConnectionPointImpl 接口(interface)时出现问题

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:37:15 24 4
gpt4 key购买 nike

我们有一个 native C++ 应用程序,它支持一些基于 COM 的各种类型的 VBA 宏。这些类型之一,VBAExtension , 将自身注册到核心 C++ 应用程序,从而产生(派生自的类)IConnectionPointImpl<Extension, &DIID_IExtensionEvents, CComDynamicUnkArray> 的实例.这很好用;给定适当的 VBAExtension 对象,核心和其他 VBA 宏都可以访问 IExtensionEvents 上的方法。

我们还有一个 .NET 程序集(用 C# 编写),它也在运行时加载到核心应用程序中。由于历史原因,程序集由自动运行的 VBA 宏加载;然后,当用户按下特定按钮时,另一个 VBA 宏将运行程序集的主入口点,这将显示 System.Windows.Forms。用于进一步交互的对话框。

这就是设置。我在访问 VBAExtension 时看到一些奇怪的行为.NET 程序集中的方法。具体来说,我从程序集中的不同位置运行以下代码:

foreach (VBAExtension ve in app.Extensions)
{
System.Diagnostics.Debug.Print("Ext: " + ve.Name);
}

如果我从程序集的主要对象的构造函数中运行它;或者从程序集的主入口点(在显示对话框之前),一切都很好——我得到了 VBAExtension 的名称打印出来了。

但是,如果我从程序集(模态 - 我们正在调用 form.ShowDialog())WinForm 中的按钮启动的命令运行相同的代码,ve.Name都是空白。 pDispatch->Invoke IConnectionPointImpl 打来的电话子类成功(返回 S_OK),但未设置任何返回变量。

如果我将对话框更改为非模态(使用 form.Show() 调用),那么名称将再次起作用。形式的模态(模态?)似乎会影响 IConnectionPointImpl调用成功。

有人知道这是怎么回事吗?

编辑:自第一次发帖以来,我已经证明重要的不是调用堆栈;相反,它是调用是否来自模式对话框。我已经更新了正文。

编辑 2:Per Hans Passant 的回答,以下是他的诊断问题的答案:

  • 正如预期的那样,在良好(无模式)情况下,如果我重命名 VBA 事件处理程序,则不会出现错误。该调用不返回任何数据。
  • 我已将 MsgBox 调用放入 VBA 处理程序;它在无模式情况下显示,但在模式情况下不显示。因此,处理程序不会在模态情况下执行。
  • 通过使用 Err ,我可以看出,如果我们在 VBA 处理程序中遇到异常,我们会得到一个 VBA 错误对话框。一旦清除它,C++ Invoke调用具有 0x80020009(“发生异常”)作为返回码,并且 pExcepInfo 填充了通用故障值(VBA 吞没了实际细节)
  • 该事件不会在模态对话框的第二次显示时触发,无论是紧随第一个对话框还是在第二次调用 C# 插件期间。

下一步我将尝试深入研究我们的消息循环。

最佳答案

这个问题中几乎没有确凿的事实可以作为答案。可能是非常简单的事情,可能是一个令人讨厌的内存损坏问题或 VBA 解释器内部对线程状态的模糊依赖。粗略的诊断是 VBA 事件处理程序根本没有运行。这在一般情况下并不少见,Basic 中用于声明事件处理程序的声明式风格几乎没有留下诊断订阅问题的好方法。许多 VBA 程序员在尝试解决“为什么事件处理程序未运行”这样的问题时都头晕目眩。

首先收集一些确凿的事实并将它们添加到您的问题中:

  • 首先验证您的 C++ 代码是否确实可以看到根本没有事件处理程序。使用好的版本,重命名事件处理程序。期望是您不这样做,引发接收器未订阅的事件不是错误。
  • 验证事件处理程序是否在错误版本中实际执行。让它做一些除了分配 BSTR 参数之外的事情,有些你可以很容易地看到磁盘上的文件。
  • 验证您是否可以正确诊断事件处理程序中的异常。分配 Err 对象并验证您的 C++ 代码是否生成正确的诊断。请注意,您的 IDispatch::Invoke() 调用为 pExcepInfo 传递了 NULL,这不是生成诊断的好方法。
  • 检查事件是否在您显示窗口时第二次运行,如果是,则说明执行顺序有问题。

稍微关注一下 ShowDialog()。这种方法确实有很多副作用。不再起作用的第一件事是 C++ 代码中的消息循环。现在是分派(dispatch)消息的 .NET 消息循环。查看您的副作用,比简单的 GetMessage/DispatchMessage() 做更多的工作。这项工作不再完成。还要在您的代码库中搜索 PostThreadMessage(),这些消息会在 .NET 代码运行时掉落在地板上。

请记住,当 C# 代码调用 ShowDialog() 时,您的 native C++ 代码将失去控制。在您关闭窗口之前,它不会重新获得控制权。这可能会触发一个简单的执行顺序问题,您的 C++ 代码在执行使 C# 代码运行的所有操作后不应执行任何重要操作。

关于c# - 从通过模态 WinForms 调用的 C++ 调用 IConnectionPointImpl 接口(interface)时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32997005/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com