Как передать массив из COM обратно в Visual Basic?

Это должно быть просто. Но я не нахожу решения. Может быть, потому что он такой старый (VB и COM)

Я пытаюсь вернуть небольшой массив целых чисел (или даже просто байтов, как я пробовал в этом примере для вопроса) COM-зарегистрированной внутрипроцессной DLL, написанной на C с использованием ATL, в приложение VB6.

Я действительно нашел много информации о том, чтобы пойти другим путем.

Насколько я понимаю, VARIANT - это решение, поскольку просто массив на основе C, переданный обратно в приложение VB, должен быть упорядочен и должен иметь известный размер.

У меня есть то преимущество, что я разрабатываю COM-объект, а также тестирую его в приложении VB. Хотя мой навык работы с VB близок к нулю.

Десятки других вызовов работают, как и ожидалось, отправляя данные и получая целые числа или BSTR из DLL COM и используя их в VB. Однако этот массив необработанных значений не работает.

Сначала я подумал, что неправильно кодирую VB, потому что очень мало знаю о VB. Затем я подумал, что это должен быть код C, который неправильно создает массив VARIANT. Теперь я не знаю, что думать.

Мои результаты заключаются в том, что вызов в VB возвращается, а в окнах VB Watch отображается VARIANT, но без содержимого (буквально пустое, не описываемое как «пустой» или «null» или что-то еще). (Почему VB настаивает на том, чтобы первая буква переменной была заглавной, можно только догадываться...)

Когда я пытаюсь получить доступ к индексу из VARINAT, происходит сбой с выходом индекса за пределы.

Я попробовал «ReDim» и получил больше ВАРИАНТОВ, все говорят «пусто». Но, по крайней мере, они говорят мне «пустой».

Таким образом, похоже, что ВАРИАНТ, возвращающийся из DLL, ничего не содержит.

Я попробовал несколько VT_ из заголовка OLE и либо получил пустой VARIANT, либо получил ошибку, что «тип автоматизации не поддерживается».

Код C++ на COM-сервере приведен ниже (очищен для публикации). Я пробовал типы VT_UI1, VT_UI4, VT_INT и некоторые другие:

STDMETHODIMP CClass::getArrayData(VARIANT* pVal, long *result) {
    unsigned char arry[4];
    unsigned long count;
    unsigned char *pData;
    arry[0] = 5; arry[1] = 6; arry[2] = 7; arry[3] = 8;     //  Just throw some data in
    count = 4;
    *result = count;

    pVal->vt = VT_ARRAY |VT_UI1;                            //   A VT of type unsigned bytes+array
    pVal->parray = SafeArrayCreateVector(VT_UI1,0,count);   //  Create 4 elements
    SafeArrayAccessData(pVal->parray, (void**) &pData);     //  Lock the memory for access
    memcpy(pData, arry, count * sizeof(unsigned char));     //  Copy the bytes in
    SafeArrayUnaccessData(pVal->parray);                    //  Release it
    return S_OK;                                            //  And we're happy...
}

Запись IDL для этого

[id(13), helpstring("method getArrayData")] HRESULT getArrayData([out] VARIANT* pVal, [out, retval] long * result);

Код ВБ:

Private Sub getdata_Click()
    Dim result As Integer
    Dim data() As Variant
    Dim value As Integer
    Dim strvalue As String

    result = mInterface.getArrayData(data)
    value = data(1)
    strvalue = CStr(value)
    ListBox.AddItem (" " + strvalue)
End Sub

Приложение VB возвращает значение 4, поэтому я знаю, что многое работает. Но в массиве ничего нет.

У меня нет идей. Цель здесь состоит в том, чтобы вернуть очень небольшой массив значений в VB, чтобы приложение VB могло получить к ним доступ с помощью индексации: данные (0), данные (1), данные (2) ....

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

Любая помощь ТИА.

Скотти

Я не думаю, что data должен быть массивом Variant, я думаю, что это должен быть скаляр Variant (который затем содержит массив). Вы выполняете переключение на VB, изменяя тип элемента с Variant на (что-то еще).

Craig 18.11.2022 21:52

Я бы немного нервничал из-за доступа к чему-либо на pVal как существующему, когда у него есть out в IDL. Это может быть или не быть безопасным.

Craig 18.11.2022 21:55

И я бы держался подальше от любых типов элементов, которые не имеют родного типа VB. Я бы не стал доверять VB правильному поведению с чем-либо беззнаковым, и я не помню, существует ли целочисленный тип VB размером в байт. Я думаю, что подписанные I2 или I4 должны быть безопасными.

Craig 18.11.2022 21:56

@Craig Спасибо за эти советы. Это было очищено для этого вопроса. Фактические данные представляют собой 32-битные целые числа, которые будут проверены конечным продуктом. VB был просто моим тестовым инструментом для проверки работы службы COM. И, надеюсь, чему-то научиться.

SpacemanScott 19.11.2022 21:38
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
4
4
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы были недалеки от решения. С вашим определением getArrayData вы можете просто вызвать его из VB следующим образом:

Dim b As Variant
Dim result As Integer
result = mInterface.getArrayData(b)

Однако вы также можете определить его как свойство в .idl, например:

[id(2), propget] // note propget
HRESULT ArrayData([out, retval] VARIANT* pVal);

как это в C/C++ (вам не нужен результат, так как массив является самоописательным):

HRESULT STDMETHODCALLTYPE get_ArrayData(VARIANT* pVal) ...

и так в ВБ:

Dim a As Variant
a = mInterface.ArrayData

Вот часы VB для вариантов a и b:

PS: VB(6) устарел, а COM нет, он до сих пор везде используется в Windows :-)

Благодарить. Мне пришлось изучить ваш ответ поближе, вы должны были сказать: «Уберите скобки из объявления Variant». Это был вариант, который я не пробовал. Кроме того, спасибо за совет по возврату массива, я тоже надеялся сделать что-то подобное.

SpacemanScott 19.11.2022 21:47

Другие вопросы по теме