Передача массива структур из C ++ (COM) в C # - PullRequest
1 голос
/ 07 ноября 2011

Я пытаюсь передать массив структур из C ++ (COM) в C #

        //C++ definition
        //MyStruct being a COM Visible Structure 
        HRESULT GetArrofStruct([in,out] LONG* count, [out,size_is(,*pnCnt)] MyStruct** ppArr);

        //C# definition
        void GetArrofStruct(ref int Count,out IntPtr outPtr);

        //I use the Function Something like this in C#

        IntPtr buffer = IntPtr.Zero;

        int Count;

        GetArrofStruct(ref Count,out buffer);
        MyStruct[] arrayManaged = new MyStruct[Count];

        for (int i = 0, nElemOffs = (int)buffer; i < Count; i++)
        {
            ru[i] = (MyStruct)Marshal.PtrToStructure((IntPtr)nElemOffs, typeof(MyStruct));
            nElemOffs += Marshal.SizeOf(typeof(MyStruct));
        }  

В цикле for первый элемент корректно распределяется, для второго элемента я получаю AccessViolation.

На стороне C ++ массив, кажется, правильно заполнен. (Проверено отладкой).

Ответы [ 2 ]

0 голосов
/ 07 ноября 2011

Что ж, ваша проблема в (int) приведении буфера.Оператор + отличается от int и IntPtr.Посмотрите на следующее:

   for (int i = 0; i < Count; i++)
   {
      IntPtr newPtr = buffer + i * sizeof(typeof(MyStruct));
      ru[i] = (MyStruct)Marshal.PtrToStructure(newPtr, typeof(MyStruct));
   } 

Я не проверял это, и я не знаю, правильно ли и правильно ли размещено содержимое вашего IntPtr, но именно так вы должны проходить по массиву структур.

Что касается проблемы с маршалингом, маршалинг определяется IDL, поэтому, пожалуйста, проверьте определение вашего массива.Я не уверен (массивы всегда смущали меня), но мне кажется, что у вас слишком много одного измерения.Попробуйте следующее (и, пожалуйста, дайте мне знать, если один правильный):

[out,size_is(pnCnt)] MyStruct** ppArr

[out,size_is(*pnCnt)] MyStruct* ppArr
0 голосов
/ 07 ноября 2011

Вы используете указатель указателя, поэтому вам просто нужно увеличить смещение (nElemOffs) на размер указателя, а не на размер структуры и разыменовать его.

Пояснение:

Вы используете MyStruct** на стороне C ++ вместо MyStruct*, это означает, что вам необходимо разыменовать его перед преобразованием значения указателя в структуру.

Пример кода:

int Count;
IntPtr pBuffer;

GetArrofStruct(ref Count,out pBuffer);
MyStruct[] arrayManaged = new MyStruct[Count];
unsafe
{
    Int32 buffer = (int)pBuffer;

    for (int i = 0; i < Count; i++)
    {
        // Read the memory position of the structure
        Int32 p = *((Int32*)buffer);
        arrayManaged[i] = (MyStruct)Marshal.PtrToStructure((IntPtr)p, typeof(MyStruct));

        buffer += 4; // increase by pointer size
    }  
}

Небольшое примечание:

Убедитесь, что ваша структура MyStruct имеет одинаковый размер на стороне C # и C ++, здесь может помочь [StructLayout(..)].

...