Страница 2 из 7

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

Добавлено: 29 июн 2007, 17:20
Absurd
Romeo писал(а):Самый просто вариант для случая, когда нужно вернуть указатель на свою структуру - это создать ещё один COM объект, который поддерживает интерфейс, состоящий из набора пропертей. Причём каждый проперти соответствует полю из структуры. Имплементация обекта - тривиальна. Проперти привязывается к внутренней переменной - эхтим имплементация и ограничивается.
Это в том случае если язык поддерживает COM без Automation - насчет 1с у меня сомнения.
В MSVC COM-коклассы с dual интерфейсом можно лабать элементарно, но в билдере я этого не делал.

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

Добавлено: 02 июл 2007, 08:05
Ivan093
Romeo писал(а):Самый просто вариант для случая, когда нужно вернуть указатель на свою структуру - это создать ещё один COM объект, который поддерживает интерфейс, состоящий из набора пропертей. Причём каждый проперти соответствует полю из структуры. Имплементация обекта - тривиальна. Проперти привязывается к внутренней переменной - эхтим имплементация и ограничивается.

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

Если понадобиться возвращать массив из таких объектов, то нужно использовать SAFEARRAY из IUnknown поинтеров.

Вот и вся кухня.
Спасибо всем за помощь. Видимо так и буду делать. Посмотрел тут один activex там массивы структур возвращаются как com-объект, у которого есть методы такие как MoveNext(), MoveFirst(), getValue(0), getValue(1) и т.д. Т.е. надо делать что-нибудь подобное...

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

Добавлено: 02 июл 2007, 09:15
Ivan093
Тут еще походу вопросы возникли :)
1. "Добавить новый COM объект" -- это я добавляю новый интерфейс IInfo с типом IUnknown?
2. Как вернуть из метода getInfo() основного интерфейса IDispatch ссылку на новый COM объект c типом IUnknown?
Создаю процедуру в главном интерфейсе getInfo() добавляю параметр Param[out, retval]. Какой тип ставить у Param (IUnknown* и IInfo* не дает ставить)?
Какой код добавить в try{ }, чтобы вернуть ссылку на мой новый COM объект?

STDMETHODIMP TMapScreenXImpl::get_Info()
{
try
{

}
catch(Exception &e)
{
return Error(e.Message.c_str(), IID_IMapScreenX);
}
return S_OK;
};

Спасибо за ответы!

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

Добавлено: 02 июл 2007, 12:01
Absurd
Ivan093 писал(а):Тут еще походу вопросы возникли :)
1. "Добавить новый COM объект" -- это я добавляю новый интерфейс IInfo с типом IUnknown?
Не знаю как это в борланде выгдядит, в Visual C++ надо создать объект с dual интерфейсом, чтобы методы кокласса были доступны одновременно через COM интерфейс и через IDispatch. IDispatch - это инструмент для скриптовых языков типа 1с, который позволяет вызывать методы не пользуясь COM-интерфейсом, просто с помощью имени функции в виде строки символов и параметрами в виде массива вариантов.

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

Добавлено: 03 июл 2007, 07:36
Ivan093
Absurd писал(а):Не знаю как это в борланде выгдядит, в Visual C++ надо создать объект с dual интерфейсом, чтобы методы кокласса были доступны одновременно через COM интерфейс и через IDispatch. IDispatch - это инструмент для скриптовых языков типа 1с, который позволяет вызывать методы не пользуясь COM-интерфейсом, просто с помощью имени функции в виде строки символов и параметрами в виде массива вариантов.
Пффф... Немного запутался. Я тут смотрел исходники activex (только хедеры и tlb, плюс юзал ее в скомпилированном виде в 1с) там есть интерфейс (с parent IUnknown), который в 1с виден как com-объект (возвращает табличку) со своими методами. У этого интерфейса не было кокласса. А есть еще там другие интерфейсы с parent IDispatch, вот у них есть кокласс, они тоже видны как com-объекты со своими методами.
Т.е. я пока сделал так:
1. для возврата нового com-объекта создал новый интерфейс пусть будет Interface1 (parent IUnknown. Или нужно IDispatch?)
2. добавил этому интерфейсу проперти и методы.
3. в главном интерфейсе создал метод, который будет возвращать новый com-объект, основанный на Interface1 (возвращаемое значение поставил IUnknown**, так было в рассмотренной мной activex. Или нужно другой тип ставить?). Вот тут-то и не понятно как его (новый объект) создать тут и вернуть. Класс Interface1 абстрактный и при попытке создать новый instance на основе этого класса возникает ошибка. Вот тут я и застрял...
Это у меня все в борланде, но думаю в VC++ все примерно так же...

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

Добавлено: 03 июл 2007, 08:34
Absurd
Ivan093 писал(а):Пффф... Немного запутался. Я тут смотрел исходники activex (только хедеры и tlb, плюс юзал ее в скомпилированном виде в 1с) там есть интерфейс (с parent IUnknown), который в 1с виден как com-объект (возвращает табличку) со своими методами. У этого интерфейса не было кокласса. А есть еще там другие интерфейсы с parent IDispatch, вот у них есть кокласс, они тоже видны как com-объекты со своими методами.
Той COM должен предоставлять одновременно два интерфейса - Interface1 унаследованный от IUnknown _и_ IDispach. Как это сделать зависит от библиотеки - с VCL помочь боюсь не могу. В MFC используются вложенные классы, а в ATL - множественное наследование C++.
Ivan093 писал(а): 1. для возврата нового com-объекта создал новый интерфейс пусть будет Interface1 (parent IUnknown. Или нужно IDispatch?)
Оба (см. выше)
От IDispatch наследуется расширение функционала IDispatch. Расширяет его только Микрософт. Я знаю только IDispatchEx для высокодинамичных скриптовых языков.
Ivan093 писал(а): 3. в главном интерфейсе создал метод, который будет возвращать новый com-объект, основанный на Interface1 (возвращаемое значение поставил IUnknown**, так было в рассмотренной мной activex. Или нужно другой тип ставить?). Вот тут-то и не понятно как его (новый объект) создать тут и вернуть. Класс Interface1 абстрактный и при попытке создать новый instance на основе этого класса возникает ошибка. Вот тут я и застрял...
Возвращаемое значение должно быть VARIANT содержащий IDispatch. COM-объекты создаются при помощи CoCreateInstance.

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

Добавлено: 03 июл 2007, 09:38
Ivan093
Absurd писал(а):Той COM должен предоставлять одновременно два интерфейса - Interface1 унаследованный от IUnknown _и_ IDispach. Как это сделать зависит от библиотеки - с VCL помочь боюсь не могу. В MFC используются вложенные классы, а в ATL - множественное наследование C++.
В билдере тоже используется ATL. Несмотря на то, что мой ActiveX создан на основе VCL компонента, я думаю, ATL там поддерживается, т.к. там есть в проекте файл *_ATL, а в нем директивы такие как #define USING_ATL, #include <atl\atlimpl.cpp>, #include <atl\atlvcl.cpp>
Absurd писал(а): Оба (см. выше)
От IDispatch наследуется расширение функционала IDispatch. Расширяет его только Микрософт. Я знаю только IDispatchEx для высокодинамичных скриптовых языков.
Там в билдере можно выбрать только один парент интерфейс, НО при этом на закладке Flags стоят флажки Ole Automation и Dual. Так что, будем считать, что дуальный интерфейс поддерживается :)
Absurd писал(а): Возвращаемое значение должно быть VARIANT содержащий IDispatch. COM-объекты создаются при помощи CoCreateInstance.
Мммм... А можно маааленький примерчик кода? :) Как создать объект, заполнить его и вернуть его в переменной VARIANT*.

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

Добавлено: 04 июл 2007, 03:05
Absurd
Ivan093 писал(а):Мммм... А можно маааленький примерчик кода? :) Как создать объект, заполнить его и вернуть его в переменной VARIANT*.
И что же вы думаете? Наваял от нефиг делать.
Испытывал на таком VBS скрипте:

Set root = CreateObject("AtlSample.Root")
Set element = CreateObject("AtlSample.Element")
element.x = 0
element.y = 1
element.z = 2
root.property1 = element
Wscript.Echo root.property1.x
Wscript.Echo root.property1.y
Wscript.Echo root.property1.z

Вывод:
0
1
2

Обнаружил что VBS не умеет работать с SAFEARRAY, что позволяет задать вопрос: нахрен SAFEARRAY тогда нужны?. Придется делать OLE Automation объект с методами типа GetFirst, GetNext в качестве замены массива.
Кроме того судя по IDL, Visual C++ дуальные интерфейсы наследует все таки от IDispatch (т.е в прошлом сообщении я наврал).

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

Добавлено: 04 июл 2007, 13:19
Ivan093
Absurd писал(а):И что же вы думаете? Наваял от нефиг делать.
Испытывал на таком VBS скрипте:

Set root = CreateObject("AtlSample.Root")
Set element = CreateObject("AtlSample.Element")
element.x = 0
element.y = 1
element.z = 2
root.property1 = element
Wscript.Echo root.property1.x
Wscript.Echo root.property1.y
Wscript.Echo root.property1.z

Вывод:
0
1
2

Обнаружил что VBS не умеет работать с SAFEARRAY, что позволяет задать вопрос: нахрен SAFEARRAY тогда нужны?. Придется делать OLE Automation объект с методами типа GetFirst, GetNext в качестве замены массива.
Кроме того судя по IDL, Visual C++ дуальные интерфейсы наследует все таки от IDispatch (т.е в прошлом сообщении я наврал).
А почему не умеет работать то, я что-то не понял? :confused: Ведь ты присвоил x=0, y=1, z=2, а VBS тебе и вернул эти значения...

Далее...
Спасибо за пример и код. В целом он понятен, но вот для моего случая (вложил .tlb), я так и не понял :( как в методе Method1 интерфейса IInterface1 создать объект с интерфейсом IInterface1, заполнить его long Property1 и VARIANT_BOOL Property2, затем вернуть объект. Т.е. чтобы из скриптового языка можно было написать:

Set obj = CreateObject("Project1.Interface1")
Set o = obj.Method1()
Wscript.Echo o.Property1
Wscript.Echo o.Property2
i = o.Какой-нибудь_метод()
и т.д.

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

[
  uuid(BBDEBC42-9E20-40AD-8704-60C02D062091), 
  version(1.0), 
  helpstring("Project1 Library")
    
]
library Project1
{

  importlib("stdole2.tlb");
  importlib("stdvcl40.dll");
  importlib("stdvcl40.dll");

  [
    uuid(0B20ABDC-13B2-4B34-ACCC-C2678A4AD6B4), 
    version(1.0), 
    helpstring("Dispatch interface for Interface1 Object"), 
    dual, 
    oleautomation
  ]
   interface IInterface1: IDispatch
  {
    [
    id(0x00000001)
    ]
    HRESULT _stdcall Method1([out, retval] VARIANT * Val );
  };

  [
    uuid(29AE9F1F-1A88-4EC8-8BA2-35A5179016C7), 
    version(1.0), 
    helpstring("Interface1 Object")
  ]
  coclass Interface1
  {
    [default] interface IInterface1;
  };

  [
    uuid(1533910F-F645-4811-813B-A6FE150DD302), 
    version(1.0), 
    helpstring("Dispatch interface for Interface2 Object"), 
    dual, 
    oleautomation
  ]
   interface IInterface2: IDispatch
  {
    [
    propget, 
    id(0x00000001)
    ]
    HRESULT _stdcall Property1([out, retval] long * Value );
    [
    propget, 
    id(0x00000002)
    ]
    HRESULT _stdcall Property2([out, retval] VARIANT_BOOL * Value );
  };

  [
    uuid(4317B5C7-4948-44EC-8758-17639BC9DEC8), 
    version(1.0), 
    helpstring("Interface2 Object")
  ]
  coclass Interface2
  {
    [default] interface IInterface2;
  };

};

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

Добавлено: 04 июл 2007, 15:05
Romeo
&quot писал(а):Обнаружил что VBS не умеет работать с SAFEARRAY, что позволяет задать вопрос: нахрен SAFEARRAY тогда нужны?.
Позволяет, Absurd. Достаточно создать обычный VBScript массив и передать его в качестве параметра в метод. VBScript Array - это и есть SAFEARRAY. Правда существует одна тонкость: при передаче через COM этот массив пакуется в VARIANT, причём пакуется ещё и по ссылке. Но это не большая проблема. Достаточно продэбажить один раз, чтобы все тонкости работы VBScript Engine стали очевидны.