Маршаллинг потока VC ++ и COM: приложение вызывало интерфейс, который был маршалирован для другого потока - PullRequest
2 голосов
/ 29 августа 2010

My VC ++ 2005 Приложение, основанное на диалоге, инициализирует COM-объект в диалоговом классе и использует его в рабочем потоке.

Я позвонил CoInitialize (NULL) В начале приложения и в начале рабочего потока.Но когда COM-метод вызывается, возникает ошибка «Приложение, названное интерфейсом, который был назначен для другого потока».

Если я использую CoInitializeEx (0, COINIT_MULTITHREADED), тогда я получу то же сообщение об ошибке

Пожалуйста, помогите мне найти основную причину.

Спасибо.

Ответы [ 3 ]

4 голосов
/ 29 августа 2010

Вы создали две однопоточные квартиры, вызвав CoInitialize (NULL). Указатель интерфейса должен быть маршалирован из одной квартиры в другую, прежде чем его можно будет использовать. Инициализация рабочего потока как MTA не решает проблему. Первоначальный указатель интерфейса все еще создавался в однопоточной квартире и поэтому не является поточно-ориентированным. Другими словами, вы не можете вызывать методы интерфейса напрямую из потока. Эти вызовы должны быть направлены в поток, который создал интерфейс. Маршалинг указателя на интерфейс устанавливает сантехнику, которая делает это возможным.

Единственный раз, когда вам не нужно маршалировать, это когда оба потока являются MTA. Это почти никогда не возможно, ваш основной поток должен быть STA, если он создает какие-либо окна. И COM-сервер должен был бы быть поточно-ориентированным, они очень редко бывают. Они рекламируют то, что им нужно, с ключом ThreadingModel в реестре. COM фактически создаст поток STA, если необходимо найти хороший дом для сервера.

Вы должны упорядочить указатель с помощью CoMarshalInterThreadInterfaceInStream (), чтобы избежать ошибки. Это довольно недружественная функция, IGlobalInterfaceTable проще в использовании. COM-сервер также должен поддерживать его, обычно вам нужна DLL-библиотека прокси / заглушки, которая занимается маршалингом. Вы получите E_NOINTERFACE, если это не так.

Также остерегайтесь накладных расходов, маршалинг вызова из рабочего потока в основной поток довольно дорог и зависит от того, насколько отзывчивым является ваш основной поток. Другими словами, если вы написали поток, чтобы ускорить вашу программу или избежать блокировки пользовательского интерфейса, то это на самом деле не будет работать. Это принцип «нет бесплатного обеда».

1 голос
/ 30 августа 2010

Я думаю, что одним из способов доступа к COM-объектам в другом потоке было бы использование указателей глобального интерфейса.После инициализации сформируйте указатель GIT на поток вместе со значением dwCookie.Затем внутри потока переинтерпретируйте-приведите указатель как DWORD и передайте его в таблицу GI, чтобы получить наш COM-указатель.

Спасибо

1 голос
/ 29 августа 2010

Вероятно CoMarshalInterface () и CoUnMarshalInterface () - самый простой способ сделать это.

Посмотрите на http://support.microsoft.com/kb/206076. Вы можете скачать кодпример и найти различные реализации ваших требований в Client.cpp.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...