Как вернуть из ActiveX-компонента структуру или массив?

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
Ivan093
Сообщения: 54
Зарегистрирован: 28 июн 2007, 13:59
Откуда: Екатеринбург
Контактная информация:

06 июл 2007, 11:20

Еще вопрос возник. Когда я в таком коде:

Код: Выделить всё

   CComObject<TInterface2> *Obj = new CComObject<TInterface2>;
   Obj->Param = 12345678;
   //Заполняем дальше экземпляр класса
   //..............

   CComVariant tmp(Obj);
   return tmp.Detach(ReturnValue);
Создал COM-объект Obj, заполнил его свойства и вернул, то как долго он будет жить (экземпляр класса)?
Например, я пишу на VBS так:

Set obj = Interface1.MyMethod(); //Получил com-объект
MsgBox obj.Param
i = 12345
obj.SetSomeParam(i)

т.е. изменяю объект, вызывая его методы, тем самым изменяются свойства в классе...
Надеюсь понятно объяснил :)
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 июл 2007, 13:59

&quot писал(а):Давай на пальцах - в чем заключается удаление варианта содержащего IDispatch? Вызывающий очевидно должен сделать QueryInterface(IID_IDispatch) или AddRef(), увеличив счетчик ссылок на объект на единицу, а получающий - сделать Release() когда интерфейс больше не нужен чтобы не случился Interface Leak. VariantClear() очевидно делает Release если вариант имеет тип VT_UNKNOWN или VT_DISPATCH.
Нет, не так. Вот схема:

Код: Выделить всё

// Вызывающий создал объект и положил его в смартпоинтер (Количество ссылок 0+1 = 1)
// Вызывающий поместил объект в Вариант (1+1 = 2)
// Вызов метода
////// Получающий проанализировал данные
////// Скажем ему нужен полученный объект, значит он сохраняет его в смартпоинтере-мэмбере, это влечёт за собой AddRef (2+1 = 3)
// Конец вызова метода
// Вызывающий удаляет Вариант (3-1 = 2)
// Вызыващий удаляет смарпоинтер (2-1 = 1)
И так: если объект был не интересен Получающему, то на последней строчке схемы объект умрёт. Но так, как Получающему он был интересен и Получающий сделал ему AddRef для дальнейшей работы с ним - объект по прежнему жив с количеством ссылок = 1.

Объект умрёт лишь тогда, когда станет неинтересен Получающему и он сделает для него Release. Это может произойти насильно, либо во время смерти Получающего, когда отработает смартпоинтер-мэмбэр, который держит наш объект.

Такая схема работы с инпут параметрами является классической.

Ситуации, когда Вызывающий делает AddRef, а Получающий делает соответствующий Release быть не должно. Это грубое нарушение концепции COM.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 июл 2007, 14:03

&quot писал(а):Создал COM-объект Obj, заполнил его свойства и вернул, то как долго он будет жить (экземпляр класса)?
Например, я пишу на VBS так:

Set obj = Interface1.MyMethod(); //Получил com-объект
MsgBox obj.Param
i = 12345
obj.SetSomeParam(i)
Будет жить до конца блока видимости obj переменной.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

06 июл 2007, 14:41

Ivan093 писал(а):Еще вопрос возник. Когда я в таком коде:
CComObject<TInterface2> *Obj = new CComObject<TInterface2>;
Тут кстати ошибка - объект Obj это не сам Сом-объект а обертка которая его запускает. Ты его создаешь через new и не удаляешь. В резeльтате Memory Leak.
2B OR NOT(2B) = FF
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

06 июл 2007, 14:49

Romeo писал(а):Нет, не так. Вот схема:

Код: Выделить всё

// Вызывающий создал объект и положил его в смартпоинтер (Количество ссылок 0+1 = 1)
// Вызывающий поместил объект в Вариант (1+1 = 2)
// Вызов метода
////// Получающий проанализировал данные
////// Скажем ему нужен полученный объект, значит он сохраняет его в смартпоинтере-мэмбере, это влечёт за собой AddRef (2+1 = 3)
// Конец вызова метода
// Вызывающий удаляет Вариант (3-1 = 2)
// Вызыващий удаляет смарпоинтер (2-1 = 1)
И так: если объект был не интересен Получающему, то на последней строчке схемы объект умрёт. Но так, как Получающему он был интересен и Получающий сделал ему AddRef для дальнейшей работы с ним - объект по прежнему жив с количеством ссылок = 1.
А если получающий работает в контексте другого треда не получиццо так что интерфейс "заинтересует" его уже после того как вызывающий удалит объект этот самый интерфейс представляющий?
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 июл 2007, 14:50

&quot писал(а):Тут кстати ошибка - объект Obj это не сам Сом-объект а обертка которая его запускает. Ты его создаешь через new и не удаляешь. В резeльтате Memory Leak.
Нет, нету memory leak. Объект создаётся с количеством ссылок = 0. ComVariant делает 0+1=1. Обёртка снаружи метода после своей смерти делает 1-1=0 и объект успешно умирает.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 июл 2007, 14:59

Ты со мной споришь, или с концепцией COM? Это не я придумал, Absurd :)

Кстати, а как ты себе представляешь этот код? Создали объект, потом пустили треду, которая вызывает некий метод, который получает этот объект, как параметр. Так? А главный процесс сразу после создания треды убил объект. Так? Ну так это кривой программный код. И не поможет в это случае ни классический подход передачи параметров, ни тот, который изобрёл и пытаешься отстаивать ты :)

Самый главный минус твоего подхода это то, что парные вызовы AddRef и Release происходят на разных уровнях вложенности. Это не только мало эстетично, это просто чревато множеством проблем.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ivan093
Сообщения: 54
Зарегистрирован: 28 июн 2007, 13:59
Откуда: Екатеринбург
Контактная информация:

06 июл 2007, 15:00

Absurd писал(а):Тут кстати ошибка - объект Obj это не сам Сом-объект а обертка которая его запускает. Ты его создаешь через new и не удаляешь. В резeльтате Memory Leak.
Хммм... Поставил я delete Obj; перед строчкой
return tmp.Detach(ReturnValue);

И при попытке обратиться к этой функции ошибка Память не может быть "read".
Ничччего не понимаю (с)...
Ivan093
Сообщения: 54
Зарегистрирован: 28 июн 2007, 13:59
Откуда: Екатеринбург
Контактная информация:

06 июл 2007, 15:01

Romeo писал(а):Нет, нету memory leak. Объект создаётся с количеством ссылок = 0. ComVariant делает 0+1=1. Обёртка снаружи метода после своей смерти делает 1-1=0 и объект успешно умирает.
Да, похоже что так и есть. Т.к. если добавить delete Obj, то вообще ничего не работает.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

06 июл 2007, 15:08

Кстати, Ivan093, Obj - это как раз и есть сам COM объект. Никакая это не обёртка. Тэмплэйт параметр является бызовым классом. Такой подход называется виртуальным наследованием и повсеместно использутся в ATL.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Ответить