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

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

Ответить
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

04 июл 2007, 15:29

Romeo писал(а):Позволяет, Absurd. Достаточно создать обычный VBScript массив и передать его в качестве параметра в метод. VBScript Array - это и есть SAFEARRAY. Правда существует одна тонкость: при передаче через COM этот массив пакуется в VARIANT, причём пакуется ещё и по ссылке. Но это не большая проблема. Достаточно продэбажить один раз, чтобы все тонкости работы VBScript Engine стали очевидны.
Возвращал из метода VARIANT содержащий SAFEARRAY каждый из элементов которого был VT_DISPATCH. VBS сцуко нопесал при попытке сделать

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

root.property1(0).x
что "Объект не является Collection'ом".
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

04 июл 2007, 17:26

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

04 июл 2007, 17:29

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

05 июл 2007, 08:49

Привет всем!
Методом научного тыка разобрался и научился возвращать com-объект, не знаю правильно или нет, но работает :)
Вот так сделал:

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

STDMETHODIMP TInterface1Impl::Method1(VARIANT* pVal)
{
  try
  {
    CComObject<TInterface2> *ccom = new CComObject<TInterface2>;
    CComVariant tmp(ccom);
    return tmp.Detach(pVal);
  }
  catch(Exception &e)
  {
    return Error(e.Message.c_str(), IID_IInterface1);
  }
  return S_OK;
};
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

05 июл 2007, 09:48

Ivan093 писал(а):Привет всем!
Методом научного тыка разобрался и научился возвращать com-объект, не знаю правильно или нет, но работает :)
Вот так сделал:

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

STDMETHODIMP TInterface1Impl::Method1(VARIANT* pVal)
{
  try
  {
    CComObject<TInterface2> *ccom = new CComObject<TInterface2>;
    CComVariant tmp(ccom);
    return tmp.Detach(pVal);
  }
  catch(Exception &e)
  {
    return Error(e.Message.c_str(), IID_IInterface1);
  }
  return S_OK;
};
Я создаю так:

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

STDMETHODIMP CRoot::GetStruct(VARIANT* param)
{
	HRESULT hr = S_OK;
	memset(param, 0, sizeof(*param));
	if (!m_elementPtr) {
		hr = m_elementPtr.CoCreateInstance(__uuidof(CElement));
	}
	if (SUCCEEDED(hr)) {
		CComPtr<IDispatch> elementDispatch;
		hr = m_elementPtr.QueryInterface(&elementDispatch);
		if (SUCCEEDED(hr)) {
			CComVariant retVal(elementDispatch);
			hr = retVal.Detach(param);
		}
	}
	return hr;
}
PS:
m_elementPtr декларироваон так:

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

CComPtr<IElement> m_elementPtr;
2B OR NOT(2B) = FF
Ivan093
Сообщения: 54
Зарегистрирован: 28 июн 2007, 13:59
Откуда: Екатеринбург
Контактная информация:

05 июл 2007, 13:41

А у меня такой вариант почему-то не работает:
hr = m_elementPtr.CoCreateInstance(__uuidof(CElement));

hr получается не равным 0. Почему -- не разобрался...
Ivan093
Сообщения: 54
Зарегистрирован: 28 июн 2007, 13:59
Откуда: Екатеринбург
Контактная информация:

05 июл 2007, 14:10

Спасибо всем за помощь, благодаря которой я быстрее разобрался с топиком. Почему-то эта тема освещена мало (судя по поискам в интернете)... Жили бы вы в моем городе -- поставил бы пива/соку :)
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

05 июл 2007, 15:34

Ivan093 писал(а):Спасибо всем за помощь, благодаря которой я быстрее разобрался с топиком. Почему-то эта тема освещена мало (судя по поискам в интернете)... Жили бы вы в моем городе -- поставил бы пива/соку :)
Потому что в этой теме вообще толком никто не разбирается - экзамен по COM/ActiveX на brainbench сдало всего 100 человек.

Например, по моему пониманию [in] параметр должен создаваться вызывающим и удаляться получающим. Но вот если входной VARIANT удалить с помощью деструктора класса CComVariant (не отдетачить значение) или напрямую с помошью VariantClear() то возникает win32 экзепшен.
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

05 июл 2007, 16:11

COM идеология подразумевает, что объект должен снимать копии со входных параметров, если ему нужно их хранить и должен создавать копии своих внутренних данных, если он должен отдать из в качестве выходного параметра.

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

06 июл 2007, 10:31

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