DispInvoke в реализации dispinterfac'а клиентом ..
От: timash  
Дата: 14.10.01 13:34
Оценка:
Здравствуйте.

Есть маленькая проблема, помогите, пожалуйста.

Хочу использовать информацию о типе об COM-обьекте на стороне клиента, чтобы минимизировать реализацию sink'а к нему. Т.е. есть COM-обьект, он сделан как реализующий Dual интерфейс, плюс к этому он еще шлет fir'ы клиенту через dispinterface. COM-обьект этот сделан самым стандартным образом — wizard'ами. Все работает, т.е. fir'ы шлются без проблем. OK.

На стороне клиента я делаю ручками sink (клиент у меня не MFC'шный, а Borland'овый еше на 3-ей версии Builder'а), и наследую его от dispinterfac'а прописанного в IDL'ке COM-обьекта. Реализую IUnknown, IDispatch и собственый рабочие функции (в IDL'ке они, безусловно, тоже определены). Все fir'ы принимается на "ура". OK.

Далее, решил я использовать в sink'овой реализации функцию DispInvoke() для вызова рабочих функций dispinterfac'а, а то собственная реализация — очень большая (так как делает перенаправления на более чем 100 рабочих функций). Т.е. в IDispatch::Invoke() просто делаю вызов DispInvoke(). Так он, зараза :-)), говорит "MEMBER IS NOT FOUND" для любых MemberID приходящих с Invoke(). Параметры pExcepInfo, puArgErr — остаются пустыми :-(( Больше инфо взять получается неоткуда :-((

Безусловно — методы все есть и раньше они спокойно работали. LoadRegTypeLib(LIBID_xxxLib) дал правильный ITypeLib*, он в свою очередь правильно отработал GetTypeInfoOfGuid(DIID__IxxxEvents) и дал ITypeInfo*. Этот указатель — корректный. Я его проверял — просил дать, к примеру, GetDocumentation() — все ОК. Остальные три метода IDispatch'а я тоже переделал — в GetTypeInfoCount() возвращаю "1", в GetTypeInfo() возвращаю ITypeInfo* и делаю к нему AddRef() делаю, в GetIDsOfNames() вызываю DispGetIDsOfNames(). Т.е. вроде все хорощо. Только не работает :-((

Вообщем не знаю куда податься :-((

P.S. Кстати, хотел спросить, что информацию о типе содержиться еще и в DLL (а не только в TLB)? А то я посмотрел по реестру, а там ссылки для coclass'ов и interfac'ов моего COM-обьекта об их библиотеке типов идут к его DLL. Т.е. могу ли я поставлять юзерам только DLL'ку (без TLB'шки) и пользоваться информацией о типе в run-time?
Re: DispInvoke в реализации dispinterfac'а клиентом ..
От: Parfenov Denis Россия  
Дата: 17.10.01 04:48
Оценка:
Здравствуйте timash, Вы писали:

T>Здравствуйте.


T>Есть маленькая проблема, помогите, пожалуйста.


T>Хочу использовать информацию о типе об COM-обьекте на стороне клиента, чтобы минимизировать реализацию sink'а к нему. Т.е. есть COM-обьект, он сделан как реализующий Dual интерфейс, плюс к этому он еще шлет fir'ы клиенту через dispinterface. COM-обьект этот сделан самым стандартным образом — wizard'ами. Все работает, т.е. fir'ы шлются без проблем. OK.


T>На стороне клиента я делаю ручками sink (клиент у меня не MFC'шный, а Borland'овый еше на 3-ей версии Builder'а), и наследую его от dispinterfac'а прописанного в IDL'ке COM-обьекта. Реализую IUnknown, IDispatch и собственый рабочие функции (в IDL'ке они, безусловно, тоже определены). Все fir'ы принимается на "ура". OK.


T>Далее, решил я использовать в sink'овой реализации функцию DispInvoke() для вызова рабочих функций dispinterfac'а, а то собственная реализация — очень большая (так как делает перенаправления на более чем 100 рабочих функций). Т.е. в IDispatch::Invoke() просто делаю вызов DispInvoke(). Так он, зараза :-)), говорит "MEMBER IS NOT FOUND" для любых MemberID приходящих с Invoke(). Параметры pExcepInfo, puArgErr — остаются пустыми :-(( Больше инфо взять получается неоткуда :-((


T>Безусловно — методы все есть и раньше они спокойно работали. LoadRegTypeLib(LIBID_xxxLib) дал правильный ITypeLib*, он в свою очередь правильно отработал GetTypeInfoOfGuid(DIID__IxxxEvents) и дал ITypeInfo*. Этот указатель — корректный. Я его проверял — просил дать, к примеру, GetDocumentation() — все ОК. Остальные три метода IDispatch'а я тоже переделал — в GetTypeInfoCount() возвращаю "1", в GetTypeInfo() возвращаю ITypeInfo* и делаю к нему AddRef() делаю, в GetIDsOfNames() вызываю DispGetIDsOfNames(). Т.е. вроде все хорощо. Только не работает :-((


T>Вообщем не знаю куда податься :-((


T>P.S. Кстати, хотел спросить, что информацию о типе содержиться еще и в DLL (а не только в TLB)? А то я посмотрел по реестру, а там ссылки для coclass'ов и interfac'ов моего COM-обьекта об их библиотеке типов идут к его DLL. Т.е. могу ли я поставлять юзерам только DLL'ку (без TLB'шки) и пользоваться информацией о типе в run-time?


Незнаю как в Builder3, а в Builder5 можно открыть функцией Open COM сервер и посмотреть все интерфейсы,функции и параметры. Скорее всего ошибка в имени или параметре функции(если я правельно понял), попробуй использовать тип Variant, у него есть такие функции OLEProcedure, OLEFunction, попробуй так.
Re[2]: DispInvoke в реализации dispinterfac'а клиентом ..
От: timash  
Дата: 18.10.01 06:38
Оценка:
Здравствуйте Parfenov Denis, Вы писали:

PD>Незнаю как в Builder3, а в Builder5 можно открыть функцией Open COM сервер и посмотреть все интерфейсы,функции и параметры. Скорее всего ошибка в имени или параметре функции(если я правельно понял), попробуй использовать тип Variant, у него есть такие функции OLEProcedure, OLEFunction, попробуй так.


Я должно быть нечетко выразился. Конкретнее: У меня был сделан ручками работающий sink, вот его код

class ChannelSink: public _IxxxEvents
{
//----------------- Methods of IUnknown -----------------------
virtual HRESULT STDMETHODCALLTYPE QueryInterface(...)
{
*ppvObject = NULL;
if(riid == IID_IUnknown) *ppvObject = static_cast<IUnknown*>(this);
else if(riid == IID_IDispatch) *ppvObject = static_cast<IDispatch*>(this);
else if(riid == DIID__IxxxEvents) *ppvObject = static_cast<_IxxxEvents*>(this);
if(*ppvObject) return S_OK; else return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; }
virtual ULONG STDMETHODCALLTYPE Release() { return 1; }
//----------------- Methods of IDispatch ----------------------
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(...) { return E_NOTIMPL; }
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(...) { return E_NOTIMPL; }
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(...) { return E_NOTIMPL; }
virtual HRESULT STDMETHODCALLTYPE Invoke()
{
if(!pDispParams) return DISP_E_PARAMNOTFOUND;
if(dispIdMember == 1)
{
if(pDispParams->cArgs != 1) return DISP_E_BADPARAMCOUNT;
if(pDispParams->rgvarg[0].vt != (VT_VARIANT | VT_BYREF)) return DISP_E_TYPEMISMATCH;
Method1(pDispParams->rgvarg[0].pvarVal);
return S_OK;
}
...
else if(dispIdMember == N) { ... MethodN(...); ... }
}
//--------- Methods of IxxxEvents interface ------------
virtual HRESULT STDMETHODCALLTYPE Method1(VARIANT* param) { ... }
...
virtual HRESULT STDMETHODCALLTYPE MethodN() { ... }
};

Он работает на "ура", т.е. принимает входящие event'ы и перенаправляет из в соответсвующие функции. OK.

Потом я решил что так как кол-во MethodN() очень большое, то надо попытаться использовать type library info об COM-обьекте который event'ы испускает, ведь там же прописан IxxxEvents интерфейс. Для этого вот что я поменял:

GetTypeInfoCount(...) { *pctinfo = 1; return S_OK; }
GetTypeInfo(...) { *ppTInfo = <полученый ранее указатель на библиотеку типов>; <он же>->AddRef(); return S_OK; }
GetIDsOfNames(...) { return DispGetIDsOfNames(..); }
Invoke() { return DispInvoke(...); }

т.е. хотел подсократить реализациюм IDispatch в клиентском sink'е. Не работает. О том как я получал и проверял указатель на библиотеку типов COM-обьекта испускающего event'ы я уже писал.
Re[3]: DispInvoke в реализации dispinterfac'а клиентом ..
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.10.01 20:23
Оценка:
Здравствуйте timash.

А IConnectonPoint и IConnectonPointContainer реализова?

И вообще зачем такие сложности для этого же есть библиотеки?


P.S. Кстати, хотел спросить, что информацию о типе содержиться еще и в DLL (а не только в TLB)? А то я посмотрел по реестру, а там ссылки для coclass'ов и interfac'ов моего COM-обьекта об их библиотеке типов идут к его DLL. Т.е. могу ли я поставлять юзерам только DLL'ку (без TLB'шки) и пользоваться информацией о типе в run-time?

Так в этом случае тлбха включается в длл как ресурс. По сути это тоже самое, что и наличие отдельной tlb. Для COM+-а отдельное хранение tlb даже приимущество (в прокси входит только она).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: DispInvoke в реализации dispinterfac'а клиентом ..
От: timash  
Дата: 22.10.01 07:12
Оценка:
Здравствуйте VladD2, Вы писали:

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

VD>А IConnectonPoint и IConnectonPointContainer реализова?


VD>И вообще зачем такие сложности для этого же есть библиотеки?


VD>Так в этом случае тлбха включается в длл как ресурс. По сути это тоже самое, что и наличие отдельной tlb. Для COM+-а отдельное хранение tlb даже приимущество (в прокси входит только она).


1. Насчет TLB'шки — очень поучительная информация. Правда. А то я долго мучился — никак понять не мог — как это ссылки указывающие на TLB указывают на DLL. Зеленый, потому что :-))
2. IConnectionPoint и IConnectionPointContainer безусловно сделаны wizard'ом и включены в COM-обьект. И мой собственноручно сделанный sink к нему advis'иться совершенно успешно. То есть event'ы приходят в sink в функцию IDispatch::Invoke() (так как исходящий default source interface это dispinterface, и, соответсвенно, ATL'ный wizard сделал Fire_Methodxxx() таким, что он пользует через вызов Invoke()). Но дело-то в том что у меня проблема не в COM-обьекте, а в sink'е, т.е. в sink этот исходящий event приходит (в функцию IDispatch::Invoke()) нормально, это проверено, но дальше перенаправляться в соответсвующию метод с помощью DispInvoke() не хочет :-((
3. Библиотеки безусловно есть — вернее макросы для построения sink'ов (в MFC — BEGIN_EVENTSINK_MAP макрос, в ATL — BEGIN_EVENTSINK_MAP макрос). Простоя я пользую C++ Builder 3.0 и там такого нет :-))

P.S. Вообщем, похоже я зря затеял все это. Мне так кажется, что поскольку source interface моего COM-обьекта — это source dispinterface, и кажется тоже что DispInvoke() не работает с чистыми dispinterface'ми, а только в dual'ными. (А, как назло, ATL'шный wizard сделал исходящий source interface как dispinterface.) Попытаюсь переделать его как dual и посмотрю что получиться ...
Re[5]: DispInvoke в реализации dispinterfac'а клиентом ..
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.10.01 19:24
Оценка:
Здравствуйте timash, Вы писали:

T>P.S. Вообщем, похоже я зря затеял все это. Мне так кажется, что поскольку source interface моего COM-обьекта — это source dispinterface, и кажется тоже что DispInvoke() не работает с чистыми dispinterface'ми, а только в dual'ными. (А, как назло, ATL'шный wizard сделал исходящий source interface как dispinterface.)


Ёоо, а слоника то я и не заметил! :) DispInvoke и ему модобные работают имглючительно с дуальными интерфейсами. DispInvoke и т.п. и есть универсальные вызывальщики кастом-чати у дуального интерфейса.

T>Попытаюсь переделать его как dual и посмотрю что получиться ...


Да, да! Должно плучиться.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.