Маршаллинг System.Array из .Net в vb6

У меня есть компонент .Net, который имеет видимый класс COM с методом, возвращающим System.Array. Под капотом он возвращает массив строк, однако тип возвращаемого значения объявлен как System.Array. Не спрашивайте меня «почему», я знаю, что могу объявить возвращаемый тип как string [], и это будет нормально, но мой вопрос в особенности, когда он возвращает System.Array. Итак, для простоты метод .Net выглядит следующим образом:

public Array GetData()
{
    return new string[] { };
}

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

Dim objRetVal As Object
Dim resData As Variant
Dim strData As String

Set objRetVal = NetClassInstance.GetData()

For Each resData In objRetVal
    strData = CStr(resData)
    MsgBox "strData = " & strData
Next

Вышеупомянутый NetClassInstance является экземпляром класса COM Visible .Net в моем компоненте .Net. Таким образом, он все время терпит неудачу, он не может маршалировать System.Array в массив строк для VB6, который я могу зацикливать и получать доступ к строкам в массиве. Обратите внимание, что objRetVal не является Nothing и не пуст, в нем есть данные, просто resData не читает строковое значение в массиве.

Я знаю, что если я верну массив строк из моего метода .Net, то он, скорее всего, будет работать на конце VB6, но я хочу знать, есть ли способ выполнить надлежащий маршалинг и преобразовать возвращенный массив System.Array в массив string () на Сторона VB6.


person Tiger Galo    schedule 06.09.2016    source источник
comment
Почему вы объявили objRetVal Object? Что не так с просто Dim retVal() As String и strArr = NetClassInstance.GetData()?   -  person Cody Gray    schedule 06.09.2016
comment
stackoverflow .com / questions / 31433552 /   -  person xxbbcc    schedule 06.09.2016
comment
VB6 требует SafeArray, вы никогда не получите этого из этого объявления. Ваш метод возвращает ссылку interface на _Array. Обычно вам также нужна ссылка на C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ mscorlib.tlb, чтобы VB6 понимал, как выглядит этот интерфейс. По-прежнему ничего вам не покупает, объявление интерфейса пустое и по-прежнему не позволяет скопировать массив. он все время терпит неудачу, недостаточно конкретен, чтобы угадать, что пойдет не так дальше. Лучше всего, чтобы не причинять себе вреда, измените тип возвращаемого значения на string [] или object [].   -  person Hans Passant    schedule 06.09.2016
comment
Почему вы пытаетесь вернуть Array вместо string[]? Что вы надеетесь получить от этого?   -  person xxbbcc    schedule 06.09.2016
comment
Я согласен, если хуже будет, я сделаю это, поскольку я владею кодом .Net, однако рассмотрим случай, когда мы не владеем кодом .Net, и мы вынуждены принять System.Array в качестве возвращаемого типа . В любом случае, похоже, что это не основная причина проблемы. Как я сказал в своем комментарии к ответу Андре, один и тот же код работает и отлично работает на одном ПК, а не на другом. Это как-то связано со средой выполнения VB или чем-то еще.   -  person Tiger Galo    schedule 06.09.2016


Ответы (2)


Все, что мне нужно было сделать, это следовать комментариям Ханса и xxbbcc, которые привели меня к подсказке, что требуется для запуска кода. Итак, я украсил свой метод следующим тегом return: MarshalAs, и у меня он хорошо сработал:

[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public Array GetData()
{
    return new string[] { };
}

Спасибо всем за поддерживающие комментарии.

person Tiger Galo    schedule 06.09.2016
comment
Это бессмысленно, когда вы выполняете в точности, возвращая string []. Хмя, если бы мы только знали, почему возвращение Array так важно. Если вы не хотите нам сообщать, просто удалите этот вопрос + ответ, он бесполезен для кого-либо еще. - person Hans Passant; 07.09.2016
comment
Как я упоминал ранее, единственная причина для поиска решения - это случай, если вы не владеете кодом .Net и не можете изменить тип возвращаемого значения. Однако, если метод украшен MarshalAs и указывает подтип как BSTR, то, по крайней мере, на стороне VB6, если objRetVal объявлен не как объект, а как массив строк, он будет преобразован. Конечно, поскольку код принадлежит мне, я определенно изменю тип возвращаемого значения на массив строк, а не на System.Array, который я унаследовал от своего коллеги. - person Tiger Galo; 07.09.2016
comment
Но все же мне интересно, как же без этой модификации старый код работал на одном ПК, а не на другом. Как VB обрабатывает _Array и преобразует его в одной системе и дает сбой в другой? - person Tiger Galo; 07.09.2016

Если я что-то не пропустил, кажется, что вы не установили никакого значения для «resdata», следовательно, возвращается пустая строка.

For Each resData In objRetVal ''Nothing to tie resdata to...
  strData = CStr(resData) ''resdata is already empty, returning nothing here...
  MsgBox "strData = " & strData
Next

Видя, что вы используете объект "resdata", должно быть что-то вроде -

resData = objRetVal.StringReturned  ''Whatever the return name might be...  

For Each resData In objRetVal ''Now has a value...
  strData = CStr(resData) ''Returning your query...
  MsgBox "strData = " & strData
Next
person AlwaysConfused    schedule 06.09.2016
comment
Ладно, становится все смешнее. Таким образом, тот же код отлично работает на другой машине. Оба имеют 64-разрядную версию Win 7 с установленной платформой .Net 4.0. Однако тот же код работает с безошибочным маршалингом на одном ПК, а не на другом (который является виртуальным образом, а не физической машиной). Теперь это дает мне подсказку, что вещи, связанные с VB, по-разному обрабатывают случай на разных ПК. - person Tiger Galo; 06.09.2016
comment
Вы работаете как администратор? - person AlwaysConfused; 06.09.2016
comment
Нет, просто обычный пользователь, хотя я только что попробовал еще один физический ПК, и он тоже вылетает с тем же поведением. Пользователь этого ПК имеет права администратора. Не знаю, что еще попробовать. - person Tiger Galo; 06.09.2016