【问题标题】:COM - .NET Interop - Winform from COM clientCOM - .NET 互操作 - 来自 COM 客户端的 Winform
【发布时间】:2009-12-07 11:33:41
【问题描述】:

我有一个包含 WinForm 的 .NET 应用程序。此 WinForm 包含一个非托管 ActiveX 控件和一些其他控件。此应用程序在独立模式下运行良好。现在我们要发布某种接口,以便可以在使用互操作功能的非托管 C++/MFC 应用程序中使用此 Winform。客户端应用程序将以非模式方式显示此表单。当用户输入详细信息时,它们会使用 COM 事件源/接收器(或连接点)方法传递给客户端。

我关注了各种文章,其中一种对我们有用的方法是 http://codebetter.com/blogs/peter.van.ooijen/archive/2005/06/03/64041.aspx

但如果我从同一个客户端应用程序启动多个线程,窗体的第二个实例会引发访问冲突异常,因为窗体上的 ActiveX 控件期望线程始终是 UI 线程(根据我的观察)。

您能否告诉我通过 Interop 向非托管客户端应用程序公开 WinForm 功能的正确方法是什么?

非常感谢

【问题讨论】:

  • 您的 WinForm 应用程序是 STA 还是 MTA?
  • 这是一个 STA,我为我创建的线程设置了正确的 Appartment 状态。

标签: .net winforms interop


【解决方案1】:

您链接的文章为您提供了在非托管应用中正确托管表单所需的所有信息。您应该在其他地方寻找 AV 的来源。通过使用调试器开始。您可以使用 Debug + Exceptions 对话框,Thrown 复选框强制它停止异常。

STA 要求几乎总是足以让 ActiveX 控件在多线程应用程序中正常运行。它保证所有方法调用都是在创建 coclass 的完全相同的线程上进行的。换句话说,coclass 实现中的任何实例变量都保证以线程安全的方式使用。

您在这里没有的一个保证是控件是否正确处理全局状态。实例变量是安全的,全局变量在不同线程中使用控件时不安全。一种可能的解决方法是为每个表单实例仅使用一个线程而不是一个 STA 线程。这有点棘手,您需要一个管理线程的不可见帮助表单。通过其 Invoke() 方法使其保持活动状态并创建新的表单实例。

在你去那里之前,先找出崩溃的原因。

【讨论】:

  • 谢谢。我相信 activex 控件明确需要一个 ui 线程。如果我从主 ui 线程实例化两个表单,它可以正常工作。我现在正在查看msdn.microsoft.com/en-us/library/ms229591(VS.80).aspx 通过上述文章,我看不到如何关闭它使用 Show 而不是 ShowDialog 显示的表单。因此,如果我调用 form.Close,则从我的互操作类中调用 Dispose 方法两次 - 一次由 Close 调用 Dispose,后者又调用 MyBase.Dispose 调用 ac_ThreadExit(参见文章),并且在此例程中显式调用 Form.Dispose .有什么帮助吗?
  • 好的,显然控件在全局状态方面存在问题。您链接的文章解决了另一个问题。一个你没有的,你已经在抽你自己的消息循环(Application.Run)。您不能直接从互操作类调用表单的 Close() 方法,它必须在正确的线程上进行。这就是为什么我建议使用不可见的辅助表单以便您可以使用它的 Invoke() 方法。
  • 谢谢。我同意并且我在调用 Close 时观察到相同的行为 - 线程不同。我将尝试实现一个不可见的帮助表单,看看这是否能解决问题。
  • 基本上,我在维护旧代码库,在业余时间我试图让设计变得更好。目前,它的设计方式并不优雅(我已经删除了很多类之间的相互依赖关系并引入了接口和事件/委托)。过去,每当我们升级到新版本的 activex 控件时,我都会设法使应用程序正常工作。在高层次上,我有一个非托管 COM EXE 服务器调用一个 .NET 应用程序(winform),该应用程序又托管一个非托管 activex 控件。该应用程序在独立模式下运行良好,问题出在我们互操作时。
【解决方案2】:

您需要将 C++/MFC 主机设置为将 apartment threading model 用于 C# 表单 COM 对象。这将通过实例化 COM 对象的原始线程序列化代理上的所有调用。您还必须使用 CoMarshalInterThreadInterfaceInStreamCoGetInterfaceAndReleaseStream 在 C++/MFC 代码中正确编组线程之间的原始接口

【讨论】:

  • 谢谢。我已经这样做了,但我认为问题出在 activeX 控件上。
猜你喜欢
  • 2012-03-31
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多