问题标签 [iconnectionpoint]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
286 浏览

c# - 从通过模态 WinForms 调用的 C++ 调用 IConnectionPointImpl 接口的问题

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

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

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

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

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

如果我将对话框更改为非模态(使用 调用form.Show()),则名称将再次起作用。表单的模态(modalness?)似乎会影响IConnectionPointImpl调用是否成功。

有谁知道发生了什么?

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

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

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

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

0 投票
1 回答
614 浏览

multithreading - IConnectionPoint::Advise 在非主线程的 Windows 10“1903”中不再起作用

我们有一个应用程序在主线程或不同线程(异步)中运行一些 COM 托管,我们希望通过使用标准 ConnectionPoint 接口连接到这个(可连接)对象以获取其事件。

直到 Windows 10 SP 1903,它确实有效。

但是,在“1903 更新”中测试应用程序 IConnectionPoint->Advise() 时,当代码在与起始线程不同的线程中运行时,CONNECT_E_CANNOTCONNECT 失败 - 在调用 Advise() 时,事件服务器会询问很多我不支持的接口,我应该只支持 IUnknown、IDispatch 和事件接口。

整个东西在非STA主线程运行的时候查询的接口很多,<1903的少,1903的有这些:

然后 Advise() 放弃并返回上面提到的错误代码。因此,我无法在与应用程序的主 STA 线程不同的线程中创建事件接收器。

更明确地说,我们有一个关系管理器应用程序,它希望在不同的线程中显示一个非模态对话框,即

  • 应用程序创建一个新线程,该线程
  • 托管然后执行的脚本,
  • 该脚本调用应用程序的一个方法(作为标准 OLE 服务器),该方法创建管理对话窗口的 OLE 控件(使用 CoCreateInstance 等)[在我假设的主 STA 线程中创建]
  • 然后脚本连接脚本线程中的控件(使用 Advise() 等),以便对话框控件可以使用脚本主机中的对象触发事件

因此,如果要进行编组,我现在的猜测是对话控件内部必须编组我传递给 Advise() 的指针,至少这是我在 WWW 的深度读到的。由于我们在这里不做任何事情,它使用标准编组器,编组正在通过 combase!CStdMarshal:CreateStub() 完成(或至少尝试这样做),这似乎不再成功。当我被要求提供一个接口(上图)时的堆栈是

我将其解释为 combase 尝试设置默认编组,并且在 1903 更新中某处失败。所以我的问题是,为什么它会失败,当我全部 Advise() 时,我的班级需要提供什么?

还是服务器(可连接对象)是在 STA 主线程中创建的,并且必须以某种方式进行更改以支持编组到调用 Advise() 的新线程的事件接收器?

在以前的版本中发现几乎相同的堆栈,但它成功了。

0 投票
1 回答
83 浏览

c++ - Windows Embedded Compact 7 上的意外 IConnectionPointImpl::Unadvise 调用

我们有一个更大的软件在 Win CE6 上运行,没有问题。核心功能在提供连接点的 COM 服务器 DLL 中实现。COM 客户端程序在程序启动时为连接点注册事件处理程序以获取状态通知等。在程序退出时,它通过调用相应的IConnectionPointImpl::Unadvise方法取消注册处理程序。

现在,我们正在移植程序以在 Win EC 7 上运行。Win EC 7 的新板支持包 (BSP) 运行良好。还有具有不同选项的不同版本,在不同时间使用来自 Microsoft 的不同来源创建,但我们的软件总是显示相同的问题。

在程序启动时,启动后约 10 秒,IConnectionPointImpl::Unadvise在所有注册的事件处理程序上被意外调用。我们的源代码中只有一个方法可以调用IConnectionPointImpl::Unadvise,而且绝对不会执行。

问题出现〜95%,但有时程序启动并运行没有问题。由于程序的大小,我们不能使用调试器,性能很差。

我们猜测,COM 运行时调用这些IConnectionPointImpl::Unadvise方法是出于某种原因。但我们不知道如何防止这种情况。

有没有人观察到同样的问题?是否有可用的解决方案/解决方法?谢谢。