Передача указателя на интерфейс в COM-объект на VB 6.0
От: tks Россия  
Дата: 14.10.02 13:16
Оценка:
Доброго времени суток. Столкнулся со следующей проблемой: Есть COM-объект написанный на VB 6.0. В этом объекте есть метод:

Public Function SetItemValue(ByRef Value As IValue, ByRef strError As String) As ErrorCode


Я пытаюсь его вызвать из программы на C++ (VC 6.0) с использованием ATL:

...
AdapterEIS::_IValuePtr val = NULL;
AdapterEIS::_IItemPtr attr = NULL;
...
attr->SetItemValue(&value, &t);


В VB приходит почему-то Nothing вместо корректного значения value. Объекты attr, value и t создаются корректно, до этого вызова я с ними успешно работаю. А вот после вызова получаю в t следующий код ошибки: Object variable or With block variable not set --- происходит исключительная ситуация в коде на VB в момент первого обращения к переменной Value.

Кто-нибудь может что-нибудь посоветовать ? Как правильно передать указатель на интерфейс ?
Программист — это не тот, кто пишет программы, а тот, чьи программы работают.
Re: Передача указателя на интерфейс в COM-объект на VB 6.0
От: George Seryakov Россия  
Дата: 14.10.02 13:46
Оценка:
Здравствуйте tks, Вы писали:

tks>
tks>Public Function SetItemValue(ByRef Value As IValue, ByRef strError As String) As ErrorCode
tks>


1. Покажи, какой idl (ну, или tlb) создается. Скорее всего, это IValue *Value, но неплохо проверить (открыв dll OleView).

tks>
tks>...
tks>AdapterEIS::_IValuePtr val = NULL;
tks>AdapterEIS::_IItemPtr attr = NULL;
tks>...
attr->>SetItemValue(&value, &t);
tks>


Я че-то не понял. Указатель на объект у тебя val, передаешь ты &value. Если параметр в методе как указано выше, то передавать нужно val.

tks>Кто-нибудь может что-нибудь посоветовать ? Как правильно передать указатель на интерфейс ?


Это не проблема. ТщательнЕе надо.
GS
Re[2]: Передача указателя на интерфейс в COM-объект на VB 6.
От: tks Россия  
Дата: 14.10.02 14:03
Оценка:
Здравствуйте George Seryakov. Все полечилось, после следующего изменения вызова:

Было:

attr->SetItemValue(&value, &t);


Стало:

AdapterEIS::_IValue *vl = value;
value->AddRef(); 
attr->SetItemValue(&vl, &t);


Но остался вопрос: зачем эти мистические действия ?

GS>1. Покажи, какой idl (ну, или tlb) создается. Скорее всего, это IValue *Value, но неплохо проверить (открыв dll OleView).


--- показываю (из OleView):

[id(0x6003000f)]
        HRESULT SetItemValue(
                        [in, out] _IValue** Value, 
                        [in, out] BSTR* strError, 
                        [out, retval] ErrorCode* );


GS>Я че-то не понял. Указатель на объект у тебя val, передаешь ты &value. Если параметр в методе как указано выше, то передавать нужно val.


--- извиняюсь там должно быть не val, а value. Это описка из-за упрощения и придания читабельности коду.

GS>Это не проблема. ТщательнЕе надо.


--- стараюсь...

Вариант использования объектов простейший — in-process, одна нить.
Программист — это не тот, кто пишет программы, а тот, чьи программы работают.
Re[3]: Передача указателя на интерфейс в COM-объект на VB 6.
От: George Seryakov Россия  
Дата: 14.10.02 14:50
Оценка:
Здравствуйте tks, Вы писали:

tks>Было:


tks>
attr->>SetItemValue(&value, &t);
tks>


tks>Стало:


tks>
tks>AdapterEIS::_IValue *vl = value;
value->>AddRef(); 
attr->>SetItemValue(&vl, &t);
tks>


tks>Но остался вопрос: зачем эти мистические действия ?


Скорее всего, приведение типа. Какой тип у value?

Можно заменить на

AdapterEIS::_IValuePtr vl = value;
attr->>SetItemValue(&vl, &t);
GS
Re[3]: Передача указателя на интерфейс в COM-объект на VB 6.
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.10.02 15:10
Оценка: 28 (2)
Здравствуйте tks, Вы писали:

tks>
tks>[id(0x6003000f)]
tks>        HRESULT SetItemValue([in, out] _IValue** Value, [in, out] BSTR* strError, [out, retval] ErrorCode* );
tks>


tks>Стало:

tks>AdapterEIS::_IValue *vl = value;
tks>value->AddRef(); 
tks>attr->SetItemValue(&vl, &t);

tks>Но остался вопрос: зачем эти мистические действия ?

А что полечилось-то?

Объяснение:
1. AdapterEIS::_IValuePtr value; // это доблестный _com_ptr_t
И когда ты передавал attr->SetItemValue(&value, здесь вызывался код из вот такого оператора _com_ptr_t, где Interface==_IValue:
    Interface** operator&() throw()
    {
        _Release();
        m_pInterface = NULL;
        return &m_pInterface;
    }

Как видишь, возвращается указатель на указтель объекта, т.е. _IValue**, но указатель на объект 1) равен NULL, а 2) разрушен через Release. Ты эту ситуацию разрулил, введя дополнительный указатель vl, который не обнуляется при взятии адреса.

2. А счетчик ссылок зачем увеличивать? А уменьшать кто будет? VB? Не дождешься!

3.И вообще зачем передавать этот параметр как ByRef? Достаточно было ByVal и без проблем в коде.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Передача указателя на интерфейс в COM-объект на VB 6.
От: tks Россия  
Дата: 14.10.02 15:16
Оценка:
Здравствуйте George Seryakov

GS> Скорее всего, приведение типа. Какой тип у value?



AdapterEIS::_IValuePtr



Видимо оператор & переопределен в _COM_SMARTPTR_TYPEDEF так, что он релизит старый указатель на интерфейс перед возвращением ссылки на него, чтобы можно было спокойно присваивать туда новое значение. Иначе как бы тогда не текла память при вызове:


CoCreateInstance(__uuidof(AdapterEIS::IValue),
                NULL,
                CLSCTX_ALL, 
                __uuidof(AdapterEIS::_IValue), (void **)&value);


В общем все понятно. Всем спасибо за внимание.
Программист — это не тот, кто пишет программы, а тот, чьи программы работают.
Re[5]: Передача указателя на интерфейс в COM-объект на VB 6.
От: George Seryakov Россия  
Дата: 14.10.02 15:19
Оценка:
Здравствуйте tks, Вы писали:

GS>> Скорее всего, приведение типа. Какой тип у value?


tks>

tks>
tks>AdapterEIS::_IValuePtr
tks>


Глюкофича _com_ptr_t. Vi2 указал. Я тебе дал неверный совет (насчет _IValuePtr).
GS
Re[4]: Передача указателя на интерфейс в COM-объект на VB 6.
От: Алекс Россия http://wise-orm.com
Дата: 15.10.02 04:00
Оценка: 4 (1)
Здравствуйте Vi2, Вы писали:

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


[]

Vi2>3.И вообще зачем передавать этот параметр как ByRef? Достаточно было ByVal и без проблем в коде.


Действительно, указатель на указатель на интерфейс передают, когда хотят, чтобы вызываемая сторона (сервер) создала объект и вернула интерфейс (можно просто вернула интерфейс без создания). При этом по переданному адресу записывается указатель на интерфейс.

У тебя ситуация противоположенная. Клиент должен передать указатель на интерфейс, чтобы сервер просто его использовал. Нет никакой необходимости передавать IInterface**. Если ты думал, что передается IInterface*, то глубоко заблуждался!

СмартПоинтеры всякие — это посуществу указатель на интерфейс. Т.е. практически все они работают по одному принципу. Я имел счастье работать с четырьмя: _com_ptr_t, CComPtr, TComInterface из BCB и еще один из книжки Робинсона. Все они имели только один член — указатель на интерфейс. Все они имели operator->() в котором возвращали этот указатель. Вообщем, вели себя как УКАЗАТЕЛЬ на интерфейс. Соответственно, чисто логически, его адрес будет указателем на указатель на интерфейс. Если ты хочешь получить просто указатель на интерфейс и работаешь с _com_ptr_t, то у него есть оператор:
        operator Interface*() const throw()
    { 
        return m_pInterface; 
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.