12

我有一个 COM 服务器(C++/STA(基于 MFC 的应用程序))和一个 COM 客户端(C#/MTA)。COM 服务器必须存在于 STA 中,因为它是一个 MFC 应用程序(我在这件事上别无选择)。客户端向服务器发出调用,服务器向客户端发出回调。这就是错误发生的地方(RPC_E_CANTCALLOUT_ININPUTSYNCCALL)。我猜如果服务器是 MTA,这个问题永远不会出现,但遗憾的是,MFC 的文档明确否认将公寓初始化为 MTA。

关于如何解决这个问题的任何想法?

我一直在玩弄让服务器对象(我通过运行对象表公开的对象)存在于它自己的公寓 (MTA) 中的想法。这是一个好主意,还是先尝试一些更简单的方法?

更新

服务器对象只是应用程序中某些功能的一个薄接口点。大多数情况下,它只是读取和写入内存位置,但在某些情况下,它会为应用程序中的各个窗口生成窗口消息。服务器对象本身并不是整个应用程序。

4

3 回答 3

18

RPC_E_CANTCALLOUT_ININPUTSYNCCALL意味着您试图从处理程序中为通过SendMessage. 这是为了帮助避免某些死锁情况。您有许多选项,归结为“避免在 SendMessage 处理程序中调用 COM”:

  • 您可以使用PostMessage为自己排队一条消息,并在该发布的消息处理程序中调用 COM 回调。
  • 您可以使用异步 DCOM,并避免阻塞消息处理程序中的调用结果。
  • 您可以编组回调接口,然后从线程池工作项调用它。因为它独立于主应用程序的消息循环,所以它不会在 SendMessage 调用中,甚至可以在 MTA 中。
  • 您可以放弃 MFC COM 支持,直接从另一个线程调用CoRegisterClassObject 。这意味着对服务器 COM 对象的任何调用都将从 COM 线程池(或者,如果您使用 STA 线程,则从该线程)调用,而不是从 MFC UI 线程调用,因此您需要使用 Windows 消息进行通信跨线程;但是如果您需要向客户端进行同步调用,这可能是最好的方法。
于 2011-07-07T19:39:41.350 回答
2

无论我多么曲折,当我被客户端调用时,我都无法将自己从应用程序中的 STA 上下文中删除。如果我在 MTA 中托管服务器对象并不重要,我仍然必须遵守 COM 的法则。在这种情况下,STA 是一个非常讨厌的“惩教设施”。我过得很辛苦...

这使我走上了一条相当丑陋的道路,但它确实有效。我没有使用 COM 与客户端进行通信,而是将自己的通信路径手动滚动到托管服务器对象和回调引用的 MTA。我基本上是通过设置一个调用队列(带有要发送的参数的 STL 容器)来创建自己的编组代码,MTA 线程拾取该队列并将其传递给客户端。然后将响应返回到响应初始调用的代码。同步是使用 Win32 事件对象完成的。

幸运的是,我需要介绍的回调并不多,而且机制的本质是静态的,只会用于我自己的目的(不会在生产环境中运行)。

哇...有时我想知道如果我选择成为木匠会是什么样的生活。

于 2011-07-07T19:29:37.680 回答
0

You can create a timer when you get the message and then do your COM calls and further processing in your TimerProc/WinProc under WM_TIMER. This works for me.

于 2016-07-24T05:31:18.707 回答