возврат массивов из COM-объекта и клиенты late binding
От: mich_ael http://www.basstream.ru
Дата: 27.05.03 11:41
Оценка:
Есть примерно следующий код в проекте ATL VS.NET:

// idl
[propget, id(1), helpstring("property")] HRESULT PropName([out, retval] VARIANT* pVal);

// реализация

STDMETHODIMP ClassName::get_PropName(VARIANT* pVal)
{    
  
  VariantInit(pVal);
  pVal->vt = VT_ARRAY | VT_BSTR;
  SAFEARRAY* psa;
  SAFEARRAYBOUND bounds = {4, 0};
  psa = SafeArrayCreate(VT_BSTR, 1, &bounds);
  
  BSTR* pBstrStrings;
  SafeArrayAccessData(psa, (void**)&pBstrStrings);
  
  for(UINT i = 0; i < psa->rgsabound->cElements; i++) {
    pBstrStrings[i] = SysAllocString(L"SomeString");
  }  
  SafeArrayUnaccessData(psa);
  pVal->parray = psa;
  
  return S_OK;
}


код клиента раннего связывания:

Dim obj As New ClassName
MsgBox obj.PropName(0) ' все работает прекрасно


как только снимаем ссылку в проекте на билиотеку и пишем

Dim obj As Object
Set obj = CreateObject("Lib.Object")
MsgBox obj.PropName(0) ' все умерло


сразу выдается ошибка "Wrong number of arguments or invalid property assignment".

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

В чем проблема?

Спасибо.
Re: возврат массивов из COM-объекта и клиенты late binding
От: Vi2 Удмуртия http://www.adem.ru
Дата: 27.05.03 12:07
Оценка:
Здравствуйте, mich_ael, Вы писали:

_>В чем проблема?

В разной обработке выражения obj.PropName(0).

При неизвестном виде объекта obj обработка идет через GetIDsOfNames и Invoke. Причем имя метода PropName и параметры: 0 — 0. Всего один параметр. GetIDsOfNames возвратит, что такой метод имеется. И этому методу будут переданы параметры (какой-то, скорее всего, Integer или VT_I2) 0. Но метод не имеет (входных) параметров. Это ошибка обрашения к методу.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: возврат массивов из COM-объекта и клиенты late bindin
От: mich_ael http://www.basstream.ru
Дата: 27.05.03 12:37
Оценка:
Здравствуйте, Vi2, Вы писали:

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


Vi2>

_>>В чем проблема?

Vi2>В разной обработке выражения obj.PropName(0).

Vi2>При неизвестном виде объекта obj обработка идет через GetIDsOfNames и Invoke. Причем имя метода PropName и параметры: 0 — 0. Всего один параметр. GetIDsOfNames возвратит, что такой метод имеется. И этому методу будут переданы параметры (какой-то, скорее всего, Integer или VT_I2) 0. Но метод не имеет (входных) параметров. Это ошибка обрашения к методу.



Однако это не метод. Это свойство возвращает массив.
Re[3]: Функция или свойство ?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 27.05.03 12:48
Оценка:
Здравствуйте, mich_ael, Вы писали:

_>Однако это не метод. Это свойство возвращает массив.

А ты можешь различить их? Я лично не берусь (без IDL/TLB описания).
a = p.Method(22,33)
a = p.Property(22,33)

Скрипты вообще над этим много не раздумывают — передают обобщенный индекс INVOKE_FUNC | INVOKE_PROPERTYGET для вызова функции-свойства, если не могут определить вид.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[3]: Возврат массива ли?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 27.05.03 12:51
Оценка:
Здравствуйте, mich_ael, Вы писали:

_>... Это свойство возвращает массив.

Дополнительно. Это свойство возвращает не массив, а Вариант. В котором ты передаешь массив, но можешь передать и не массив. Например, строку. Или число. Так что применение (0) после имени свойства просто не оправдано.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Возврат массива ли?
От: mich_ael http://www.basstream.ru
Дата: 27.05.03 13:29
Оценка:
Здравствуйте, Vi2, Вы писали:

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


Vi2>

_>>... Это свойство возвращает массив.

Vi2>Дополнительно. Это свойство возвращает не массив, а Вариант. В котором ты передаешь массив, но можешь передать и не массив. Например, строку. Или число. Так что применение (0) после имени свойства просто не оправдано.

Ага. Чисто теоретически я все понял, но практической реализации того, что мне нужно не представляю. Если не затруднит показать как мне надо написать код, чтобы в итоге я получал нужный мне массив (а тем паче пояснить почему надо делать так, или иначе) — буду весьма признателен.
Re: возврат массивов из COM-объекта и клиенты late binding
От: George Seryakov Россия  
Дата: 27.05.03 13:48
Оценка:
Здравствуйте, mich_ael, Вы писали:

_>
...
_>  psa = SafeArrayCreate(VT_BSTR, 1, &bounds);
_>


_> как только снимаем ссылку в проекте на билиотеку и пишем

_>В чем проблема?

Позднее связывание понимает массивы VT_VARIANT. Не знаю, как насчет бейсика, а вот для передачи массива во всякие скрипты это — единственный вариант.
GS
Re[5]: Возврат массива ли?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 27.05.03 14:06
Оценка:
Здравствуйте, mich_ael, Вы писали:

_>Чисто теоретически я все понял, но практической реализации того, что мне нужно не представляю. Если не затруднит показать как мне надо написать код, чтобы в итоге я получал нужный мне массив (а тем паче пояснить почему надо делать так, или иначе) — буду весьма признателен.

Вариантов несколько. Я их привожу, но не проверяю.

  1. Dim v
    v = obj.PropName 
    MsgBox v(0)


  2. MsgBox obj.PropName()(0)
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Возврат массива ли?
От: mich_ael http://www.basstream.ru
Дата: 27.05.03 14:38
Оценка:
Работает и так и сяк.

1) можно ли сделать что-нибудь для того, чтобы избежать конструкции типа obj.PropName()(0), вместо нее вызывать просто элемент массива по индексу obj.PropName(0)?
2) В скрипте vbs получаю Type mismatch. Что сделать, чтобы пофиксить?
Re[7]: Возврат массива ли?
От: Vi2 Удмуртия http://www.adem.ru
Дата: 28.05.03 04:32
Оценка:
Здравствуйте, mich_ael, Вы писали:

_>1) можно ли сделать что-нибудь для того, чтобы избежать конструкции типа obj.PropName()(0), вместо нее вызывать просто элемент массива по индексу obj.PropName(0)?

Конечно, можно. Разделить муху и котлету. Результат вызова свойства сохрани в переменной и используй ее. Но можешь поэкспериментировать в направлении
[propget, id(1), helpstring("property")] HRESULT PropName([in,optional] VARIANT index, [out, retval] VARIANT* pVal);

с возвратом i-ого элемента вместо массива при задании индекса.

_>2) В скрипте vbs получаю Type mismatch. Что сделать, чтобы пофиксить?

Смотреть, что тебе посоветовал George Seryakov, а именно — массив в скриптах должен содержать варианты, а не строки.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re: Проблема решена
От: mich_ael http://www.basstream.ru
Дата: 28.05.03 08:59
Оценка:
STDMETHODIMP ClassName::get_PropName(VARIANT* pVal)
{    
  
  VariantInit(pVal);
  pVal->vt = VT_ARRAY | VT_BSTR;
  SAFEARRAY* psa;
  SAFEARRAYBOUND bounds = {4, 0};
  psa = SafeArrayCreate(VT_BSTR, 1, &bounds);
  
  BSTR* pBstrStrings;
  SafeArrayAccessData(psa, (void**)&pBstrStrings);
  
  for(UINT i = 0; i < psa->rgsabound->cElements; i++) {
    
    // было так
    //pBstrStrings[i] = SysAllocString(L"SomeString");
    //
    // а надо так
    pBstrStrings[i].vt = VT_BSTR;
    pBstrStrings[i].bstrVal = SysAllocString(L"Hello");


  }  

  SafeArrayUnaccessData(psa);
  pVal->parray = psa;
  
  return S_OK;
}


я не сообразил, что каждому элементу массива надо явно указать подтип VARIANT.

Всем огромное спасибо.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.