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

发布于 2024-11-19 01:20:41 字数 473 浏览 3 评论 0原文

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

关于如何解决这个问题有什么想法吗?

我一直在考虑让服务器对象(我通过运行对象表公开的对象)居住在它自己的公寓(MTA)中。这是一个好主意,还是有更简单的方法可以先尝试?

更新

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

I have a COM server (C++/STA (MFC based app)) and a COM client (C#/MTA). The COM server must live in an STA, since it's an MFC app (I have no choice in this matter). The client issues a call to the server, and the server issues a callback to the client. That's where the error happens (RPC_E_CANTCALLOUT_ININPUTSYNCCALL). I'm guessing if the server had been an MTA, this problem would never have arised, but sadly, the documentation for MFC explicitly denies initializing the apartment as an MTA.

Any ideas on how to work around this problem?

I have been toying with the idea of letting the server object (the object I expose through the running object table) live in an apartment of its own (MTA). Would this be a good idea, or is there something simpler to try first?

UPDATE

The server object is just a thin interface point to certain functions within the application. Most of the time it just reads and writes to memory locations, but there are instances where it generates window messages to various windows within the application. The server object itself is not the entire application.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我很坚强 2024-11-26 01:20:41

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

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

RPC_E_CANTCALLOUT_ININPUTSYNCCALL means that you attempted to make a marshalled COM call from within the handler for a windows message sent via SendMessage. This is to help avoid certain deadlock situations. You have a number of options, which boil down to "avoid COM calls in a SendMessage handler":

  • You could use PostMessage to queue up a message to yourself, and in that posted message handler, invoke the COM callback.
  • You could use asynchronous DCOM, and avoid blocking on the result of the call from within the message handler.
  • You could marshal the callback interface, then invoke it from a thread pool work item. Since this is independent from the main application's message loop, it won't be in a SendMessage call, and it could even be in a MTA.
  • You could forgo the MFC COM support, and invoke CoRegisterClassObject directly from another thread. This means any calls into your server COM object will be invoked from the COM thread pool (or, if you use a STA thread, from that thread), not from the MFC UI thread, so you'll need to use Windows messages to communicate across threads; but if you need to make synchronous calls back to the client it may be the best approach.
笑红尘 2024-11-26 01:20:41

无论我如何扭转,当客户端呼叫我时,我都无法将自己从应用程序内的 STA 上下文中删除。如果我将服务器对象托管在 MTA 中并不重要,我仍然必须遵守 COM 规则。在这种情况下,STA 确实是一个令人讨厌的“惩教所”。我正在努力……

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

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

哎哟...有时我想知道如果我选择成为一名木匠,生活会是什么样。

No matter how much I twist and turn, I cannot remove myself of the STA context within the app when I'm being called from the client. It doesn't matter if I host the server object in an MTA, I still have to obey the laws of COM. The STA is a really nasty "correctional facility" in this case. I'm doing hard time...

This has led me to a rather ugly path, but it works. Instead of using COM to communicate back to the client, I'm hand rolling my own communications path to the MTA that hosts the server object and the callback references. I'm basically creating my own marshalling code by setting up a call queue (STL container with parameters to send), which the MTA thread picks up and delivers to the client. The response is then returned to the code that's responding to the initial call. Synchronization is done using Win32 event objects.

Luckily, there aren't many callbacks I have to cover, and the nature of the mechanism is static, and will only be used for my own purposes (will not be run in a production environment).

Wheew... Sometimes I wonder what life would've been if I chose to become a carpenter instead.

若无相欠,怎会相见 2024-11-26 01:20:41

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文