Вызов методов из COM-dll`ки
От: Eugene Sh Россия  
Дата: 09.07.03 11:49
Оценка:
У меня такая проблема.
Есть COM`овская dll`ка, написанная на C++. Внутри dll`ки вызывается CoInitializeEx(NULL, COINIT_MULTITHREADED) — там необходимо использовать многопоточную модель.
При вызове методов dll`ки из приложения, написанного на C++, всё нормально. А при вызове из приложения, написанного на VB, CoInitializeEx возвращает ошибку RPC_E_CHANGED_MODE — "cannot change thread mode after it is set".
Вызов делается так:
Dim a As Object
Set a = CreateObject("XXX.XXX")
a.TestCoInitEx

Кто-нибудь сталкивался с этим? Как вызвать из VB методы многопоточной COM`овской dll`ки?
Re: Вызов методов из COM-dll`ки
От: Tom Россия http://www.RSDN.ru
Дата: 09.07.03 14:04
Оценка:
Здравствуйте, Eugene Sh, Вы писали:

ES>У меня такая проблема.

ES>Есть COM`овская dll`ка, написанная на C++. Внутри dll`ки вызывается CoInitializeEx(NULL, COINIT_MULTITHREADED) — там необходимо использовать многопоточную модель.
ES>При вызове методов dll`ки из приложения, написанного на C++, всё нормально. А при вызове из приложения, написанного на VB, CoInitializeEx возвращает ошибку RPC_E_CHANGED_MODE — "cannot change thread mode after it is set".
ES>Вызов делается так:
ES>Dim a As Object
ES>Set a = CreateObject("XXX.XXX")
ES>a.TestCoInitEx

ES>Кто-нибудь сталкивался с этим? Как вызвать из VB методы многопоточной COM`овской dll`ки?

Проблемма возникает из за того, что VB уже инициализировал аппартамент как STA. Вызывать обьекты, находящиеся в MTA нужно так же как и те, которые в STA. т.е просто вызывать их, но не забыть их правильно зарегистрировать.

ЗЫ: Обычно при реализации обьекта в dll не надо вызывать CoInitialize так как CoInitialize обычно вызывает или клиент COM обьекта или подсистема COM не явно.
Народная мудрось
всем все никому ничего(с).
Re[2]: Вызов методов из COM-dll`ки
От: Eugene Sh Россия  
Дата: 09.07.03 14:27
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Здравствуйте, Eugene Sh, Вы писали:


ES>>У меня такая проблема.

ES>>Есть COM`овская dll`ка, написанная на C++. Внутри dll`ки вызывается CoInitializeEx(NULL, COINIT_MULTITHREADED) — там необходимо использовать многопоточную модель.
ES>>При вызове методов dll`ки из приложения, написанного на C++, всё нормально. А при вызове из приложения, написанного на VB, CoInitializeEx возвращает ошибку RPC_E_CHANGED_MODE — "cannot change thread mode after it is set".
ES>>Вызов делается так:
ES>>Dim a As Object
ES>>Set a = CreateObject("XXX.XXX")
ES>>a.TestCoInitEx

ES>>Кто-нибудь сталкивался с этим? Как вызвать из VB методы многопоточной COM`овской dll`ки?

Tom>Проблемма возникает из за того, что VB уже инициализировал аппартамент как STA. Вызывать обьекты, находящиеся в MTA нужно так же как и те, которые в STA. т.е просто вызывать их, но не забыть их правильно зарегистрировать.

Sorry за непонятливость, но что значит "просто вызывать их, но не забыть их правильно зарегистрировать"?
Re[3]: Вызов методов из COM-dll`ки
От: Tom Россия http://www.RSDN.ru
Дата: 09.07.03 14:40
Оценка:
ES>Sorry за непонятливость, но что значит "просто вызывать их, но не забыть их правильно зарегистрировать"?

Dim MyObj as MyMultiThreadedObject
MyObj.MyMethod


Зарегестрировать — в реестре правильно. Т.е указать поточную модель или free или both
... << RSDN@Home 1.1 beta 1 >>
Народная мудрось
всем все никому ничего(с).
Re[4]: Вызов методов из COM-dll`ки
От: Eugene Sh Россия  
Дата: 09.07.03 15:09
Оценка:
Здравствуйте, Tom, Вы писали:

ES>>Sorry за непонятливость, но что значит "просто вызывать их, но не забыть их правильно зарегистрировать"?


Tom>
Tom>Dim MyObj as MyMultiThreadedObject
Tom>MyObj.MyMethod
Tom>


Tom>Зарегестрировать — в реестре правильно. Т.е указать поточную модель или free или both


Ясно. Но проблема в следующем.
Вызов методов то происходит нормально, но вот работают они не так как надо.
Вызывается CoCreateInstance для объектов, лежащих в другой dll, являющейся многопоточной. И CoCreateInstance из-за несовпадения моделей потоков возвращает ошибку E_NOINTERFACE.

В реестре у меня прописано both.
Re[5]: Вызов методов из COM-dll`ки
От: Tom Россия http://www.RSDN.ru
Дата: 09.07.03 15:18
Оценка:
Здравствуйте, Eugene Sh, Вы писали:

ES>Здравствуйте, Tom, Вы писали:


ES>>>Sorry за непонятливость, но что значит "просто вызывать их, но не забыть их правильно зарегистрировать"?


Tom>>
Tom>>Dim MyObj as MyMultiThreadedObject
Tom>>MyObj.MyMethod
Tom>>


Tom>>Зарегестрировать — в реестре правильно. Т.е указать поточную модель или free или both


ES>Ясно. Но проблема в следующем.

ES>Вызов методов то происходит нормально, но вот работают они не так как надо.
ES>Вызывается CoCreateInstance для объектов, лежащих в другой dll, являющейся многопоточной. И CoCreateInstance из-за несовпадения моделей потоков возвращает ошибку E_NOINTERFACE.

ES>В реестре у меня прописано both.


Это кто тебе сказал, что E_NOINTERFACE возникает из за этого? E_NOINTERFACE означает, что QueryInterface этого обьекта не нашёл запрашиваемого интерфейса.
... << RSDN@Home 1.1 beta 1 >>
Народная мудрось
всем все никому ничего(с).
Re[6]: Вызов методов из COM-dll`ки
От: Eugene Sh Россия  
Дата: 09.07.03 15:29
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Здравствуйте, Eugene Sh, Вы писали:


ES>>Здравствуйте, Tom, Вы писали:


ES>>>>Sorry за непонятливость, но что значит "просто вызывать их, но не забыть их правильно зарегистрировать"?


Tom>>>
Tom>>>Dim MyObj as MyMultiThreadedObject
Tom>>>MyObj.MyMethod
Tom>>>


Tom>>>Зарегестрировать — в реестре правильно. Т.е указать поточную модель или free или both


ES>>Ясно. Но проблема в следующем.

ES>>Вызов методов то происходит нормально, но вот работают они не так как надо.
ES>>Вызывается CoCreateInstance для объектов, лежащих в другой dll, являющейся многопоточной. И CoCreateInstance из-за несовпадения моделей потоков возвращает ошибку E_NOINTERFACE.

ES>>В реестре у меня прописано both.

Tom>
Tom>Это кто тебе сказал, что E_NOINTERFACE возникает из за этого? E_NOINTERFACE означает, что QueryInterface этого обьекта не нашёл запрашиваемого интерфейса.

Да. Но когда я вызываю свою dll из программы, написанной на C++, CoInitializeEx(NULL, COINIT_MULTITHREADED) проходит нормально(возвращает S_FALSE, т.е. уже была инициализирована именно во многопоточной модели), и в дальнейшем вызов CoCreateInstance проходит нормально. В чём может быть дело?
Re[7]: Вызов методов из COM-dll`ки
От: Tom Россия http://www.RSDN.ru
Дата: 09.07.03 15:54
Оценка:
ES>Да. Но когда я вызываю свою dll из программы, написанной на C++, CoInitializeEx(NULL, COINIT_MULTITHREADED) проходит нормально(возвращает S_FALSE, т.е. уже была инициализирована именно во многопоточной модели), и в дальнейшем вызов CoCreateInstance проходит нормально. В чём может быть дело?

Да не ломай себе голову. Поставь бряк. поинт в QueryInterface и всё.
... << RSDN@Home 1.1 beta 1 >>
Народная мудрось
всем все никому ничего(с).
Re[8]: Вызов методов из COM-dll`ки
От: Eugene Sh Россия  
Дата: 09.07.03 16:17
Оценка:
Здравствуйте, Tom, Вы писали:

ES>>Да. Но когда я вызываю свою dll из программы, написанной на C++, CoInitializeEx(NULL, COINIT_MULTITHREADED) проходит нормально(возвращает S_FALSE, т.е. уже была инициализирована именно во многопоточной модели), и в дальнейшем вызов CoCreateInstance проходит нормально. В чём может быть дело?


Tom>Да не ломай себе голову. Поставь бряк. поинт в QueryInterface и всё.


Похоже, что такой вызов действительно всегда будет приводить к ошибке — кажется, нельзя из однопоточной модели вызвать объект из многопоточной dll.
Остаётся вопрос — нельзя ли из VB осуществить вызов так, чтобы моя dll загрузилась в многопоточной модели?
Re[9]: Вызов методов из COM-dll`ки
От: Tom Россия http://www.RSDN.ru
Дата: 09.07.03 16:29
Оценка:
Здравствуйте, Eugene Sh, Вы писали:

ES>Здравствуйте, Tom, Вы писали:


ES>>>Да. Но когда я вызываю свою dll из программы, написанной на C++, CoInitializeEx(NULL, COINIT_MULTITHREADED) проходит нормально(возвращает S_FALSE, т.е. уже была инициализирована именно во многопоточной модели), и в дальнейшем вызов CoCreateInstance проходит нормально. В чём может быть дело?


Tom>>Да не ломай себе голову. Поставь бряк. поинт в QueryInterface и всё.


ES>Похоже, что такой вызов действительно всегда будет приводить к ошибке — кажется, нельзя из однопоточной модели вызвать объект из многопоточной dll.

ES>Остаётся вопрос — нельзя ли из VB осуществить вызов так, чтобы моя dll загрузилась в многопоточной модели?
Молодой человек Вы сюда пришли за ответом на вопрос. Я Вам отвечаю, что не в этом дело. В чём угодно, но не в этом! Обьекты можно и нужно использовать между аппартаментами. Возможно(и скорее всего) проблемма возникает из за того, что для запрашиваемого интерфейса не зарегистрирован proxy/stub.
... << RSDN@Home 1.1 beta 1 >>
Народная мудрось
всем все никому ничего(с).
Re: Неверный вызов CoInitialize
От: Vi2 Удмуртия http://www.adem.ru
Дата: 10.07.03 08:27
Оценка:
Здравствуйте, Eugene Sh, Вы писали:

ES>У меня такая проблема.

Твоя проблема уж точно не связана с VB. Скорее это из общей тоерии СОМ и С++ в частности, т.к. неверен DLL сервер, а не VB клиент.

ES>Есть COM`овская dll`ка, написанная на C++. Внутри dll`ки вызывается CoInitializeEx(NULL, COINIT_MULTITHREADED) — там необходимо использовать многопоточную модель.

Внутри DLL-сервера допускается вызывать CoInitialize/CoInitializeEx только для созданных этой DLL потоков. Вот для них и нужно вызывать инициализацию СОМ. Все остальные вызовы неверны и должны быть отброшены (независимо работает ли правильно клиент на С++ ниже или нет).

ES>При вызове методов dll`ки из приложения, написанного на C++, всё нормально.

Значит, приложение, написанное на C++, ошибочно. А как известно существует закон парности ошибок: 2 ошибки ошибкой не считаются.

ES>А при вызове из приложения, написанного на VB, CoInitializeEx возвращает ошибку RPC_E_CHANGED_MODE — "cannot change thread mode after it is set".

А это и есть следствие неверного вызова CoInitialize/CoInitializeEx в DLL-ке.

ES>Кто-нибудь сталкивался с этим? Как вызвать из VB методы многопоточной COM`овской dll`ки?

Тут проблемы нет, и с этим сталкивался каждый. Расположение объекта в том или ином апартменте определяется его записью в Реестре (Apartment, Free или Both). Все остальные объекты или потоки сервера, которые нужны этому создаваемому объекту, уже на его совести.

PS
Код ошибки E_NOINTERFACE, который ты приводишь, связан с маршалингом в другой апартмент и преодолевается предоставлением прокси/стаба на запрашиваемый интерфейс. Или использованием [oleautomation] атрибута для твоего интерфейса и typelib-маршалинга из СОМа.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.