Как маршалировать массив структуры C++/CLI в неуправляемый C++

StackOverflow https://stackoverflow.com/questions/734996

Вопрос

Я ищу правильный синтаксис для передачи массива структур в неуправляемую dll C++.

мой импорт dll называется так

    #define _DllImport [DllImport("Controller.dll", CallingConvention = CallingConvention::Cdecl)] static
_DllImport bool _Validation(/* array of struct somehow */);

В моем клиентском коде у меня есть

List<MyStruct^> list;
MyObject::_Validation(/* list*/);

Я знаю, что в System::Runtime::InteropServices::Marshal есть много полезных методов для подобных вещей, но я не уверен, какой из них использовать.

Это было полезно?

Решение

Создайте управляемую версию неуправляемой структуры с помощью StructLayout.Sequential (обязательно расположите все в том же порядке).После этого вы сможете передать его так же, как и любую управляемую функцию (например, Validation(MyStruct[] pStructs).

Например, предположим, что наша собственная функция имеет такой прототип:

extern "C" {

STRUCTINTEROPTEST_API int fnStructInteropTest(MYSTRUCT *pStructs, int nItems);

}

а собственный MYSTRUCT определяется следующим образом:

struct MYSTRUCT
{
    int a;
    int b;
    char c;
};

Затем в C# вы определяете управляемую версию структуры следующим образом:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MYSTRUCT
{
    public int a;
    public int b;
    public byte c;
}

И управляемый прототип выглядит следующим образом:

    [System.Runtime.InteropServices.DllImportAttribute("StructInteropTest.dll", EntryPoint = "fnStructInteropTest")]
    public static extern int fnStructInteropTest(MYSTRUCT[] pStructs, int nItems);

Затем вы можете вызвать функцию, передав ей массив структур MYSTRUCT следующим образом:

    static void Main(string[] args)
    {
        MYSTRUCT[] structs = new MYSTRUCT[5];

        for (int i = 0; i < structs.Length; i++)
        {
            structs[i].a = i;
            structs[i].b = i + structs.Length;
            structs[i].c = (byte)(60 + i);
        }

        NativeMethods.fnStructInteropTest(structs, structs.Length);

        Console.ReadLine();
    }

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

Вы можете использовать Маршалл.StructureToPtr чтобы получить IntPtr, который можно было бы передать в собственный массив MyStruct*.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top