Сделал простейший COM-Server.
В клиентском MFC-приложении запускаю поток — класс, производный от CWinThread. В его InitInstance делаю СoInitialize и пытаюсь получить доступ к своему Server-у, используя SmartPointer-ы. В ответ — сообщение об ошибке (Invalid pointer = 0).При отладке — сообщение что-то типа "MYServer.dll relocated due to collision with Some.dll..."
Если все делать в рамках главного потока программы — все ОК (сообщение о collision). Но мне нужно иметь доступ к COM внутри другого потока.
Много то как, сразу и не разберешь... :)
К>Сделал простейший COM-Server.
Молодец! Так держать! :)
К>В клиентском MFC-приложении запускаю поток — класс, производный от CWinThread. В его InitInstance делаю СoInitialize и пытаюсь получить доступ к своему Server-у, используя SmartPointer-ы. В ответ — сообщение об ошибке (Invalid pointer = 0).
Совет номер 1: делай CoInitialize(...) в InitInstance(...) приложения и не забывай делать CoUninitialize(...) в ExitInstance(...) — все пока работает.
К>При отладке — сообщение что-то типа "MYServer.dll relocated due to collision with Some.dll..."
Совет номер 2: не обращай мнимания на это сообщение: у меня COM-DLL-ек штук по пять-шесть грузится и на каждую он пишет подобные страшные вещи. Что означают — не знаю — это, вон, к гуру. Знаю что на это можно не обращать внимания.
К>Если все делать в рамках главного потока программы — все ОК (сообщение о collision). Но мне нужно иметь доступ к COM внутри другого потока.
И имей доступ к своему COM внутри другого потока: CoCreateInstance(...) (или как там они на "хитрых поинтерах" создаются) — и вперед!!!
Здравствуйте The Lex, Вы писали:
К>>При отладке — сообщение что-то типа "MYServer.dll relocated due to collision with Some.dll..." TL>Совет номер 2: не обращай мнимания на это сообщение: у меня COM-DLL-ек штук по пять-шесть грузится и на каждую он пишет подобные страшные вещи. Что означают — не знаю — это, вон, к гуру. Знаю что на это можно не обращать внимания.
Это сообщение говорит о том, что DLL не может быть расположена в адресном пространстве процесса по своему предпочтительному базовому адресу, потому что это место уже занято (другой DLL или чем-то еще). Загрузчик вынужден переместить DLL в адресном пространстве процесса, что приводит к использованию дополнительного пространства в pagefile и, если более одного процесса используют эту DLL, к большему использованию физической памяти. При создании своих DLL следует стремиться к тому, чтобы они все находились по уникальным базовым адресам и не конфликтовали с другими DLL, для чего служат ключ линкера /BASE и утилита rebase.
Спасибо за сообщения
Благодаря "Пониманию подразделений COM" вроде бы разобрался.
В InitInstance потока вызываю СoInitialize() (согласно статье, каждый поток, использующий COM, должен вызывать CoInitialize[Ex]() — по-видимоиу, чтобы поместиться в к-л Apartment-e ).
Кроме того, добавил в реестр ThreadingModel=Apartment (это наверное, чтобы поместить СOM объект в тот же Apartment, где находится и создавший объект поток — в моем случае). Проверил отладчиком — вроде бы все работает.
Здравствуйте The Lex, Вы писали:
TL>И имей доступ к своему COM внутри другого потока: CoCreateInstance(...) (или как там они на "хитрых поинтерах" создаются) — и вперед!!!
Чтобы иметь доступ к апартаментному компоненту расположенному в другом апартаменте (потоке для Апартмент-компонетов) нужно или получить указатель на объект через метод отмаршаленого COM-объекта, или делать ручной маршалинг (в стрим и обратно), или использовать GIT. Иначе кроме глюков ничего не получить.
Альтернативу можно получить используя FTM.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Как запустить COM... - Спасибо, разобрался.
Здравствуйте Константин, Вы писали:
К>Спасибо за сообщения К>Благодаря "Пониманию подразделений COM" вроде бы разобрался. К>В InitInstance потока вызываю СoInitialize() (согласно статье, каждый поток, использующий COM, должен вызывать CoInitialize[Ex]() — по-видимоиу, чтобы поместиться в к-л Apartment-e ).
CoInitialize() и CoInitializeEx() как раз и создают (инициализируют апартамент).
К>Кроме того, добавил в реестр ThreadingModel=Apartment
А на чем написан сам объект? Большинство библиотек избавляют от прописывания данных в реестре.
К>(это наверное, чтобы поместить СOM объект в тот же Apartment, где находится и создавший объект поток — в моем случае). Проверил отладчиком — вроде бы все работает.
Нет это для того, чтобы COM знал, что этот объект должен загружаться в STA. Например, если создать такой объект из MTA-потока, то объект будет создан в новом апартаменте, а если в уже существующем STA (как это ты делал в самом начале), то объект будет создан в том же апартаменте. Во втором случае маршалинга не будет. Не будет и возможности параллельно обращаться к объектам созданным в одном STA.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как запустить COM... - Спасибо, разобрался.
Здравствуйте VladD2, Спасибо за ответы. Вы писали:
К>>Кроме того, добавил в реестр ThreadingModel=Apartment VD>А на чем написан сам объект? Большинство библиотек избавляют от прописывания данных в реестре.
Вообще то к своему стыду, на голом так сказать С++.
Re[4]: Как запустить COM... - Спасибо, разобрался.
Здравствуйте Константин, Вы писали:
VD>>А на чем написан сам объект? Большинство библиотек избавляют от прописывания данных в реестре.
К>Вообще то к своему стыду, на голом так сказать С++.