Re[5]: Массив как параметр события
От: Vi2 Удмуртия http://www.adem.ru
Дата: 11.10.05 03:54
Оценка: 2 (1)
Здравствуйте, dmkSar, Вы писали:

S>Объявляю метод принимающего интерфейса:

S>interface IOPCCustomDA : IUnknown
S>...
S>HRESULT AsyncWrite([in] long size, [in, size_is(size)] long ServerHandles[], 
S>                    [out, size_is(size)] long Errors[]);

S>В VB: Sub AsyncWrite(size As Long, ServerHandles As Long, Errors As Long)

S>Формирую массив SvrHndl(), вызываю из VB:
S>OPC.AsyncWrite ItemCount, SvrHndl(0), Errors(0)

Ты не только формируешь через ReDim SvrHndl(больше чем ItemCount-1), но и должен сформировать ReDim Errors(больше чем ItemCount-1). Хотя туда (в параметр Errors) можно, в забывчивости, передать обычную переменную или ошибиться с размером выделения массива Errors с КАТАСТРОФИЧЕСКИМИ последствями.

Что происходит на деле? VB передает адреса первых элементов массивов, твоя прокси/стаб DLL использует ItemCount ячеек (я использую "ячеек", не уточняя тип переменной), начиная с переданного адреса, в качестве элементов массива. Что, фактически, правильно и отражает реальное положение дел в примере.

S>Все OK, обрабатываю массив Errors().


Количество элементов, доступных для обработки, определяется не сервером (прокси/стаб DLL), как должно было быть, а оператором VB. Согласись, что что-то тут избыточно или не нужно. Ну ладно, раз обрабатывается, и тебя устраивает.

S>Объявляю метод outbound интерфейса:

S>interface _IOPCCustomDAEvents : IUnknown
S>...
S>HRESULT DataChange([in] long NumItems, [in, size_is(NumItems)] long ClientHandles[]);

S>В VB: Event DataChange(NumItems As Long, ClientHandles As Long)

Дело сразу ухудшается, раз речь заходит о вызываемом сервером методе. Тут у тебя нет рулей, которые у тебя были в случае вызова тобой сервера. Нет, например, возможности задать массив, который бы принял ClientHandles.

S>В итоге, в процедуре обработки события

S>Private Sub OPC_DataChange(ByVal NumItems As Long, ClientHandles As Long)
S> ...
S>End Sub

S>получаю ClientHandles как long-переменную, а не массив.


И это всё, конечная, приехали. Можно потыркаться, если силен в описаниях Variant-а, упаковать в него, но гарантий нет. Потому что VB волен вызвать или скопировать этот злосчастный Long, который передал сервер, как ему заблагорассудится. И связи с тем линейным участком, который передал сервер вкупе с прокси/стабом, нет и не предвидится. Почему я так могу говорить? Потому что реально сервер вызывает IDispatch::Invoke, которая в конце концов вызовет OPC_DataChange, но что будет с параметрами во время подготовки этого вызова — я не берусь говорить, тем более, что-либо предложить в качестве работоспособного кода. А не за горами VB.NET, который и объехать не даст.

Единственное, что будет точно работать, т.к. согласовано между клиентами, серверами и передающими средствами СОМа, — это SAFEARRAY.
interface IOPCCustomDA : IUnknown
...
HRESULT AsyncWrite([in] SAFEARRAY(long) *ServerHandles, [out, retval] SAFEARRAY(long) *Errors);

В VC: HRESULT AsyncWrite(SAFEARRAY/*long*/ ** ServerHandles, SAFEARRAY/*long*/ ** Errors)
В VB: Sub AsyncWrite(ServerHandles() As Long, Errors() As Long)

interface _IOPCCustomDAEvents : IUnknown
...
HRESULT DataChange([in] SAFEARRAY(long) *ClientHandles);

В VC: HRESULT DataChange(SAFEARRAY/*long*/ ** ClientHandles)
В VB: Event DataChange(ClientHandles() As Long)

Оверхед в С/С++ — вызов SafeArrayAccessData(&ptr_to_first_element) и SafeArrayUnaccessData с получением линейного массива type* ptr_to_first_element. Зато никаких танцев с бубнами в VB и иже с ним. Оверхед в прокси/стаб — в передаче с 20-30 байт управляющей информации самой структуры SAFEARRAY.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Массив как параметр события
От: dmkSar  
Дата: 10.10.05 07:30
Оценка:
Как в ATL с помощью Implement Connection Point реализовать событие, передающее клиенту массив значений? Клиент на VB 6.0 видит только первое значение и не воспринимает этот параметр как массив.
Re: Массив как параметр события
От: Vi2 Удмуртия http://www.adem.ru
Дата: 10.10.05 09:00
Оценка:
Здравствуйте, dmkSar, Вы писали:

S>Как в ATL с помощью Implement Connection Point реализовать событие, передающее клиенту массив значений?

S>Клиент на VB 6.0 видит только первое значение и не воспринимает этот параметр как массив.

Для "клиента на VB" массив с необходимостью принимает форму SAFEARRAY и передается через него. Никакой другой тип массивов OLE Automation не знает, т.е никаких [size_is] и т.п. параметров.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Массив как параметр события
От: dmkSar  
Дата: 10.10.05 11:08
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Для "клиента на VB" массив с необходимостью принимает форму SAFEARRAY и передается через него. Никакой другой тип массивов OLE Automation не знает, т.е никаких [size_is] и т.п. параметров.


Вообще, VB версии 6.0 предоставляет прямой доступ к custom-интерфейсу, мой сервер не реализует интерфейс автоматизации. Вопрос возник потому, что с передачей массива в принимающем (inbound) интерфейсе проблем нет, проблема с outbound-интерфейсом.
Re[3]: Массив как параметр события
От: Vi2 Удмуртия http://www.adem.ru
Дата: 10.10.05 11:33
Оценка:
Здравствуйте, dmkSar, Вы писали:

S>Вообще, VB версии 6.0 предоставляет прямой доступ к custom-интерфейсу, мой сервер не реализует интерфейс автоматизации.


Мы в курсе про VB6. Но не имеет значения, что "твой сервер не реализует интерфейс автоматизации", имеет значение, что VB является клиентом автоматизации и поэтому требует от сервера соответствовать.

S>Вопрос возник потому, что с передачей массива в принимающем (inbound) интерфейсе проблем нет, проблема с outbound-интерфейсом.


Лучше разговаривать предметно, на основе кода. VB клиент и при вызове сервера не передает массив через ByRef параметр As простой_тип, а только через ByRef параметр() As простой_тип, а это и есть SAFEARRAY. Это, конечно, можно объехать с помощью своей прокси/стаб, но это все равно из области трюков.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Массив как параметр события
От: dmkSar  
Дата: 10.10.05 12:33
Оценка:
Здравствуйте, Vi2.

Более подробно.
Объявляю метод принимающего интерфейса:

interface IOPCCustomDA : IUnknown
...
HRESULT AsyncWrite([in] long size, [in, size_is(size)] long ServerHandles[],
[out, size_is(size)] long Errors[]);

В браузере объектов VB получаем определение:
Sub AsyncWrite(size As Long, ServerHandles As Long, Errors As Long)

Формирую массив SvrHndl(), вызываю из VB:

OPC.AsyncWrite ItemCount, SvrHndl(0), Errors(0)

Все OK, обрабатываю массив Errors().

Объявляю метод outbound интерфейса:

interface _IOPCCustomDAEvents : IUnknown
...
HRESULT DataChange([in] long NumItems, [in, size_is(NumItems)] long ClientHandles[]);

В браузере объектов VB получаем определение:

Event DataChange(NumItems As Long, ClientHandles As Long)

В итоге, в процедуре обработки события

Private Sub OPC_DataChange(ByVal NumItems As Long, ClientHandles As Long)
...
End Sub

получаю ClientHandles как long-переменную, а не массив.
Re[6]: Массив как параметр события
От: Vi2 Удмуртия http://www.adem.ru
Дата: 11.10.05 04:13
Оценка:
Здравствуйте, Vi2, Вы писали, но неправильно:

Vi2>interface IOPCCustomDA : IUnknown
Vi2>...
Vi2>HRESULT AsyncWrite([in] SAFEARRAY(long) *ServerHandles, [out, retval] SAFEARRAY(long) *Errors);

Vi2>В VC: HRESULT AsyncWrite(SAFEARRAY/*long*/ ** ServerHandles, SAFEARRAY/*long*/ ** Errors)
Vi2>В VB: Sub AsyncWrite(ServerHandles() As Long, Errors() As Long)

Указанный вариант в VB будет для [out] SAFEARRAY(long) *Errors, а для с [retval]
В VB: Function AsyncWrite(ServerHandles() As Long) As Long()
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Массив как параметр события
От: dmkSar  
Дата: 11.10.05 09:22
Оценка:
Здравствуйте, Vi2.

Спасибо за информацию!
Этот вопрос не освещен в "Модель COM и применение ATL 3.0" Трельсена, а где подробнее расписан COM я пока не знаю.
Не подскажешь, нет ли других способов преобразования массива в SAFEARRAY кроме как:

// Имеем массив pvValues, тип VARIANT, размера dwCount
SAFEARRAY *pSA;
SAFEARRAYBOUND bounds = {dwCount, 0};
pSA = SafeArrayCreate(VT_VARIANT, 1, &bounds);
VARIANT *theVariants;
SafeArrayAccessData(pSA, (void**)&theVariants);
for (int i = 0; i < dwCount; i++) 
    theVariants[i] = pvValues[i];
SafeArrayUnaccessData(pSA);
Re[7]: Массив как параметр события
От: Vi2 Удмуртия http://www.adem.ru
Дата: 11.10.05 09:31
Оценка:
Здравствуйте, dmkSar, Вы писали:

S>Не подскажешь, нет ли других способов преобразования массива в SAFEARRAY кроме как:


SAFEARRAY на массиве C++
Автор: Сомов Александр
Дата: 14.01.04
и далее
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.