COM出站呼叫导致“由于应用程序正在调度输入同步呼叫,因此无法进行拨出呼叫。”

时间:2011-07-07 11:57:06

标签: visual-c++ com sta mta

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

有关如何解决此问题的任何想法?

我一直在想让服务器对象(我通过运行对象表公开的对象)住在自己的公寓(MTA)中。这是一个好主意,还是先尝试一些简单的东西?

更新

服务器对象只是指向应用程序中某些功能的精简界面。大多数情况下,它只是读取和写入内存位置,但有些情况下它会向应用程序中的各个窗口生成窗口消息。服务器对象本身不是整个应用程序。

3 个答案:

答案 0 :(得分:12)

RPC_E_CANTCALLOUT_ININPUTSYNCCALL表示您尝试从处理程序中为通过SendMessage发送的Windows消息进行编组的COM调用。这有助于避免某些死锁情况。您有许多选项,可以归结为“避免在SendMessage处理程序中调用COM”:

  • 您可以使用PostMessage将消息排队给自己,并在发布的消息处理程序中,调用COM回调。
  • 您可以使用asynchronous DCOM,并避免在消息处理程序中阻止调用结果。
  • 你可以marshal the callback interface,然后从thread pool work item调用它。由于这与主应用程序的消息循环无关,因此它不会在SendMessage调用中,甚至可能在MTA中。
  • 您可以放弃MFC COM支持,并直接从另一个线程调用CoRegisterClassObject。这意味着将从COM线程池(或者,如果您使用STA线程,从该线程)调用对服务器COM对象的任何调用,来自MFC UI线程的,所以你将需要使用Windows消息跨线程进行通信;但如果你需要向客户端发回同步呼叫,这可能是最好的方法。

答案 1 :(得分:0)

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

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

幸运的是,我不需要涉及很多回调,并且该机制的性质是静态的,并且仅用于我自己的目的(不会在生产环境中运行)。

Wheew ...有时候我想知道如果我选择成为一名木匠,生活会是怎样的。

答案 2 :(得分:0)

您可以在收到消息时创建计时器,然后在WM_TIMER下的TimerProc / WinProc中进行COM调用和进一步处理。这对我有用。