Исходящий вызов COM приводит к «Исходящий вызов не может быть выполнен, так как приложение отправляет синхронный входной вызов». - PullRequest
10 голосов
/ 07 июля 2011

У меня есть COM-сервер (C ++ / STA (приложение на основе MFC)) и COM-клиент (C # / MTA). COM-сервер должен жить в STA, так как это приложение MFC (у меня нет выбора в этом вопросе). Клиент отправляет вызов на сервер, а сервер отправляет обратный вызов клиенту. Вот где происходит ошибка (RPC_E_CANTCALLOUT_ININPUTSYNCCALL). Я предполагаю, что если бы сервер был MTA, эта проблема никогда бы не возникла, но, к сожалению, документация для MFC явно запрещает инициализировать квартиру как MTA.

Есть идеи, как обойти эту проблему?

Я думал о том, чтобы позволить объекту сервера (объекту, который я выставляю через таблицу запущенных объектов) жить в собственной квартире (MTA). Это будет хорошей идеей, или сначала попробуйте что-нибудь попроще?

ОБНОВЛЕНИЕ

Объект сервера - это всего лишь тонкий интерфейс с определенными функциями в приложении. Большую часть времени он просто читает и записывает в области памяти, но есть случаи, когда он генерирует оконные сообщения для различных окон в приложении. Сам объект сервера не является целым приложением.

Ответы [ 3 ]

12 голосов
/ 07 июля 2011

RPC_E_CANTCALLOUT_ININPUTSYNCCALL означает, что вы попытались выполнить маршализованный COM-вызов из обработчика для сообщения Windows, отправленного через SendMessage.Это поможет избежать определенных тупиковых ситуаций.У вас есть несколько опций, которые сводятся к тому, чтобы «избегать COM-вызовов в обработчике SendMessage»:

  • Вы можете использовать PostMessage, чтобы поставить в очередь сообщение для себя, и в этом отправил обработчик сообщений, вызовите обратный вызов COM.
  • Вы можете использовать асинхронный DCOM и избежать блокировки результата вызова из обработчика сообщений.
  • Вы можете выполнить маршалинг интерфейса обратного вызова , затем вызовите его из рабочего элемента пула потоков .Так как это не зависит от цикла сообщений основного приложения, оно не будет в вызове SendMessage и даже может быть в MTA.
  • Вы можете отказаться от поддержки MFC COM и вызвать CoRegisterClassObject прямо из другого потока.Это означает, что любые вызовы COM-объекта вашего сервера будут вызываться из пула потоков COM (или, если вы используете поток STA, из этого потока), не из потока пользовательского интерфейса MFC, поэтому вам потребуетсяиспользовать сообщения Windows для связи между потоками;но если вам нужно сделать синхронные звонки обратно клиенту, это может быть лучшим подходом.
0 голосов
/ 24 июля 2016

Вы можете создать таймер, когда получите сообщение, а затем выполните COM-вызовы и дальнейшую обработку в TimerProc / WinProc под WM_TIMER. Это работает для меня.

0 голосов
/ 07 июля 2011

Независимо от того, сколько я крутлю и поворачиваю, я не могу удалить себя из контекста STA в приложении, когда меня вызывают из клиента. Не имеет значения, если я размещаю объект сервера в MTA, я все же должен подчиняться законам COM. В данном случае STA - это действительно неприятное «исправительное учреждение». Я делаю трудное время ...

Это привело меня к довольно ужасному пути, но это работает. Вместо того чтобы использовать COM для связи с клиентом, я вручную перевожу свой собственный путь связи к MTA, на котором размещен объект сервера и ссылки на обратный вызов. Я в основном создаю свой собственный код сортировки, настраивая очередь вызовов (контейнер STL с параметрами для отправки), который поток MTA берет и доставляет клиенту. Ответ затем возвращается к коду, который отвечает на первоначальный вызов. Синхронизация выполняется с использованием объектов событий Win32.

К счастью, я не могу охватить много обратных вызовов, и механизм по своей природе статичен и будет использоваться только для моих собственных целей (не будет работать в производственной среде).

Ух ты ... Иногда я задаюсь вопросом, какой была бы жизнь, если бы вместо этого я решил стать плотником.

...