CoInitialize необходимо вызывать из каждого потока, в котором используется COM-объект, а не только из основного потока.
Прошло десять лет с тех пор, как я в последний раз автоматизировал Matlab, так что извините за ржавчину в дальнейшем. То, что вы получили сообщение об ошибке CoInitialize, предполагает, что вызов engOpen упаковывает базовые вызовы COM. К сожалению, это подвергает вас неожиданному воздействию червей, которыми является COM. Я думаю, вы правы, и что engOpen включает вызов CoInitialize, который инициализирует библиотеку COM в текущем потоке. Для доступа к COM-объектам из потока CoInitialize всегда должен вызываться в этом потоке перед любыми вызовами COM (кроме одной разрешенной функции COM, я не помню какой).
Мой совет — теперь изолировать все ваши вызовы Matlab в один поток. Если вы сделаете это, вам не придется делать явный вызов CoInitialize, и вы избежите любых последующих проблем с многопоточными COM. Вы можете заставить свою программу работать сегодня, вызвав CoInitialize во втором потоке, но однажды вы столкнетесь с другой проблемой COM.
[Я потратил около десяти лет на COM, и он полон медвежьих капканов. Вы могли бы потратить несколько недель на чтение технологии, которую Microsoft пыталась скрыть/убить с помощью .Net, но сейчас лучше просто выбрать простой (однопоточный) путь и забыть об этом.]
Обновление Боюсь, ваше редактирование завело вас в трясину моделей многопоточности COM. COINIT_MULTITHREADED эффективно сообщает COM, что вы собираетесь позаботиться обо всех мелких нюансах многопоточности, что почти наверняка не то, что вы хотите делать. COM работает с несколькими (последний раз, когда я обращал внимание, что это было три) моделями потоков, и параметр, который вы передаете CoInitializeEx, объявляет, какую из этих моделей вы хотите использовать.
Извиняюсь перед всеми, если нижеследующее немного не так.
Если вы укажете COINIT_MULTITHREADED, вам нужно либо знать, что вызываемый вами COM-объект является потокобезопасным, либо выполнить соответствующую блокировку (и маршаллинг интерфейсов и данных между потоками) самостоятельно.
COINIT_APARTMENTTHREADED, который, вероятно, использует engOpen, поскольку, по моему опыту, он наиболее распространен, позволяет библиотеке COM справляться с многопоточностью за вас. Библиотека может, например, создавать прокси-объекты и объекты-заглушки для передачи вызовов между потоками (или границами процессов, что произойдет, когда вы вызовете Matlab).
engOpen создал прокси-объект Matlab в вашем основном потоке. Этот прокси-объект можно вызвать из потока, в котором он был создан, и, если я правильно помню, из любого другого потока в «квартире» (где CoInitializeEx был вызван с COINIT_APARTMENTTHREADED.) Вы попытались вызвать через прокси из потока в другой модели многопоточности библиотека COM заметила и выдала упомянутую вами ошибку.
Во многих отношениях COM прекрасен, но его тонкости вызывают головную боль. Будьте благодарны, что вам никогда не придется использовать Distributed COM, что действительно неприятно!
Обновление 2 Мои старые воспоминания о моделях многопоточности COM ошибочны. На на этой странице MSDN указано, что на квартиру приходится один поток с COINIT_APARTMENTTHREADED. Доступ к COM-объектам можно получить с помощью одного и того же указателя интерфейса из всех потоков в подразделении, где они были созданы. Для COINIT_APARTMENTTHREADED это означает только поток, в котором был создан объект. В COINIT_MULTITHREADED это будут все потоки в многопоточном апартаменте, но (1) вы не можете выбрать, на каком потоке создается механизм Matlab, если вы используете engOpen и (2) пытаетесь вызвать COM-объект, который вы не писать из многопоточного апартамента рискованно. Первоначальная модель многопоточности OLE допускала вызовы COM только из основного потока GUI, кстати.
person
RobH
schedule
08.10.2013