Ваш исходный код C ++ нарушил договор STA.В котором указывается, что указатель интерфейса должен быть маршалирован из одного потока в другой, чтобы все вызовы объекта выполнялись только из одного потока.Это является жестким требованием для однопоточных COM-серверов, и в противном случае возникает риск типичного страдания, связанного с вызовами make из нескольких потоков в коде, который не является поточно-ориентированным.Использование двух потоков STA не освобождает вас от этого требования, объект принадлежит только потоку, который его создал.2-й поток - это просто еще один поток, и вызовы из него не могут быть сделаны безопасно, поскольку сервер не поддерживает многопоточность.
Вам как-то это не понравилось в коде C ++, трудно представить, что его не былоглюк сейчас и потом.В противном случае COM не может принудительно исполнить контракт STA на внутрипроцессных COM-серверах, только на внепроцессных серверах.Нарушение контракта порождает RPC_E_WRONG_THREAD в этом случае.
В любом случае, вам больше не сходит с рук это в программе на C #.CLR автоматически маршалирует указатель интерфейса для вас.Вызовы, которые вы делаете во 2-м потоке, будут маршалированы в поток STA, которому принадлежит объект.Чередование продолжается, но вызовы 2-го потока могут быть доставлены только тогда, когда первый поток бездействует и снова входит в цикл обработки сообщений.Обходного пути для этого не существует, обработка указателя интерфейса в CLR осуществляется строго по правилам.
Это будет иметь много последствий для вашего кода, я думаю, самое большое из них - то, что 2-й поток действительно больше ничего не выполняет.Параллелизма нет, все вызовы объекта строго сериализуются.И потокобезопасен.Вам, вероятно, будет лучше просто делать все звонки из одного потока, чтобы вам не пришлось танцевать вокруг значительного риска тупика.Создание правильной прокачки сообщений в качестве бонуса менее критично.Если 2-й поток выполняет другую критическую работу, то может быть полезно использование поддержки COM для однопоточного кода.