Как заставить MTA на всех потоках вызывать неуправляемый процесс стороннего производителя в управляемый плагин?
Я пытаюсь написать управляемый плагин для неуправляемого хост-приложения с помощью COM-взаимодействия. Все неуправляемые интерфейсы плагинов совместимы с COM, хотя COM не используется (без реестра и т. Д.). Я прошел долгий путь, чтобы заставить его работать, есть только одна вещь, которую я хотел бы изменить.
Вызовы, которые выполняются из неуправляемого хост-приложения в сборку управляемого плагина, все выполняются в STA- (управляемом) потоке. Я хотел бы, чтобы это был MTA, чтобы не было синхронизации / перекачки.
Я не могу найти способ добиться этого.
Любая помощь или предложения наиболее ценится.
РЕДАКТИРОВАТЬ: Это НЕ распространенный сценарий COM-взаимодействия: хост не COM, и никто не вызывает CoInitialize / CoCreateInstance и т. Д. Кажется, CLR назначает квартиру неуправляемому потоку, который вызывает в управляемый плагин. Это то, что я хочу изменить (теперь по умолчанию STA вместо MTA).
Связанные вопросы, которые я задал, могут предоставить больше контекста: маршалинг интерфейса взаимодействия Inter-COM(-isch) приводит к исключению AccessViotlationException при простом вызове Возвращенный метод управляемого объекта, не вызванный из C++ при взаимодействии COM
2 ответа
Вы упомянули, что в хост-приложении нет COM, и точка входа в ваш управляемый плагин является экспортируемой функцией.
Как реализована эта экспортированная функция? Я полагаю, что внутри вашего плагина есть кусок неуправляемого кода C++ для начальной загрузки управляемого кода. Если так, то это то, что вы можете сделать CoInitializeEx(NULL, COINIT_MULTITHREADED)
, теоретически. То есть вы должны сделать это перед созданием любых объектов.NET из C++ через COM-взаимодействие.
Однако это может быть очень безответственным и опасным по отношению к приложению хоста. Вы абсолютно уверены, что хост не использует COM в этом потоке (и не использует ни один из его других плагинов)? Вы уверены, что он не будет пытаться инициализировать COM на более позднем этапе?
Кроме того, если хост уже инициализировал COM в этом потоке как STA, ваш вызов CoInitializeEx
скорее всего потерпит неудачу с RPC_E_CHANGED_MODE
ошибка.
У вас нет права голоса в этом вопросе, это неуправляемое приложение хоста, которое создало поток (ы) и вызвало CoInitializeEx(), выбирая тип квартиры. Это не может быть изменено впоследствии.
Это не может быть большой проблемой, поскольку вы предлагаете поддерживать бесплатную многопоточность, если у вас все нормально с вызовами из MTA. И ThreadingModel по умолчанию для классов.NET ComVisible - Оба. Таким образом, не происходит маршалинг, когда хост вызывает вас из своего потока STA, и использование неправильного потока STA будет очень необычным.
Это имеет значение только тогда, когда вы выполняете обратные вызовы на неуправляемый хост, события являются наиболее распространенным случаем. Вы можете использовать многопоточность в своем собственном коде, но вы должны соблюдать контракт, требуемый хостом. Любые обратные вызовы, которые вы делаете, должны выполняться в потоке, в котором был создан ваш класс. Это просто сделать с помощью Control.BeginInvoke(), хост пообещал поддержать его, так как выбрал STA. Сравните, например, с событием WebBrowser.DocumentCompleted.