Передать структуру или массив строк из C ++ в C # с помощью COM - PullRequest
1 голос
/ 05 января 2011

У меня есть компонент COM (в C #), который имеет следующий интерфейс:

namespace InterOp
{
    [StructLayout(LayoutKind.Sequential)]
    public struct MyStruct
    {
        [MarshalAs(UnmanagedType.BStr)]
        public string name;
        [MarshalAs(UnmanagedType.BStr)]
        public string surname;
        public int age;
    }

    public interface ITest
    {        
        void SetStringArray(string[] array);
        void SetStructArray(MyStruct[] array);
    }

    public class Test : ITest
    {
        // string arrays
        public void SetStringArray(string[] array)
        {
            for(int i = 0; i < array.Length; i++)
                MessageBox.Show(array[i]); // just do something with the array values
        }

        // struct arrays
        public void SetStructArray(MyStruct[] array)
        {
            for (int i = 0; i < array.Length; i++)
                MessageBox.Show(array[i].name + ", " + array[i].surname + " (" + array[i].age.ToString() + ")");// just do something with the array values
        }
    }
}

Теперь я хочу передать данные из C ++ в этот COM-объект. Я инициализировал интерфейс следующим образом:

HRESULT hr = CoInitialize(NULL);
ITest* pTest = NULL;
hr = CoCreateInstance(__uuidof(Test), NULL, CLSCTX_INPROC_SERVER, __uuidof(ITest), (void**)&pTest);

Но я не могу передать ссылку на мой массив этому методу, так как для этого требуется массив SAFEARRAY *. Мне удалось создать SAFEARRAY с массивами с элементами фиксированного размера, такими как double, int, char, и это прекрасно работает, используя что-то вроде этого:

SAFEARRAY* data = SafeArrayCreate(VT_R8, 1, &bound); //8-Byte-Real, 1 dimension

Конечно, для моей пользовательской структуры нет "VT_something", поэтому я не знаю, как создать SAFEARRAY для решения этой проблемы. Я попытался VT_DISPATCH и VT_BSTR без успеха.

Фактический способ передачи данных:

bool SetStructArrayEx(MyInterOp::MyStruct* array, int arraySize, ITest* comObjectInterface)
{
    bool retVal = false;

    // Create the safearray environment
    SAFEARRAYBOUND bound;
    bound.lLbound = 0;
    bound.cElements = arraySize;

    // Init the safearray
    SAFEARRAY* data = SafeArrayCreate(VT_DISPATCH, 1, &bound); 

    // access the safearray data and copy the original data to it
    MyInterOp::MyStruct HUGEP* temp;
    HRESULT hr = SafeArrayAccessData(data, (void HUGEP* FAR*)&temp);
    if(SUCCEEDED(hr))
    {
        // finally copy the data
        for(int i=0; i<arraySize; ++i)
            *temp++ = array[i];

        comObjectInterface->SetStructArray(data);
        SafeArrayUnaccessData(data);

        retVal = true;
    }

    SafeArrayDestroy(data);

    return retVal;
}

... и это не работает (исключение в Kernel32.dll при вызове SetStructArray).

Есть идеи, где я не прав? Или что будет работать?

Спасибо, Markus

Ответы [ 2 ]

2 голосов
/ 05 января 2011

Похоже, что ваш вопрос такой же, как этот: https://stackoverflow.com/questions/268117/safearray-of-structs

В частности, см. http://vcfaq.mvps.org/com/4.htm:

  • Импорт структуры в C ++ с помощью библиотеки типов, созданной из C #
  • Вызовите SafeArrayCreateEx(VT_RECORD), SafeArrayAccessData и SafeArrayUnaccessData для заполнения массива
1 голос
/ 05 января 2011

COM имеет очень плохую поддержку структур. Как минимум, вам нужно использовать IRecordInfo, чтобы узнать расположение структуры, 4-й аргумент SafeArrayCreateEx () На самом деле не уверен, что CLR поддерживает это. Или как получить указатель на интерфейс IRecordInfo.

В противном случае ваш код C ++ имеет правильную идею. Не используйте структуру, используйте класс [ComVisible]. Члены структуры могут быть просто свойствами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...