Передача структуры в C ++ API с использованием Marshal.StructureToPtr в C # - PullRequest
15 голосов
/ 15 октября 2010

Я использую API, написанный на C ++, в моем коде (запись на C #).API требует параметр как указатель на структуру.Структура состоит из массивов "Int" и Char: например,

 unsafe public struct ToBePassed 
    { 
        Int32 Num1;
        Int32 Num2; 
        Char[] Data; // or fixed Char Data[255];
    }

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

Теперь у меня есть два варианта: 1-й: - Передача структуры по ссылке: я хочу спросить, может ли получить API, требующий указатель структурыадрес, когда я передаю структуру по ссылке.Обратите внимание, что API вернет данные в «Char [] Data».

2nd: - Использование Marshal.StructureToPtr: это преобразует указатель структуры в IntPtr.Опять же Сомнение остается тем же, правильно ли этот API получит его?

Спасибо за ваше время!

С уважением, Суонанд

1 Ответ

19 голосов
/ 15 октября 2010

Если для этого требуется только указатель, вы можете выделить некоторую неуправляемую память, упорядочить структуру в памяти и передать этот указатель в вашу функцию.Затем вы могли бы вернуться в структуру (если хотите) и освободить память.Прежде чем что-то маршалировать, нужно правильно определить структуру.Примерно так:

[StructLayout(
    LayoutKind.Sequential,      //must specify a layout
    CharSet = CharSet.Ansi)]    //if you intend to use char
public struct ToBePassed
{
    public Int32 Num1;
    public Int32 Num2;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
    public Char[] Data;    //specify the size using MarshalAs
}

[DllImport("...")]
public static extern void APICall(IntPtr argPtr);


public static void CallFunction(ToBePassed managedObj)
{
    IntPtr unmanagedAddr = Marshal.AllocHGlobal(Marshal.SizeOf(managedObj));

    Marshal.StructureToPtr(managedObj, unmanagedAddr, true);

    APICall(unmanagedAddr);

    Marshal.PtrToStructure(unmanagedAddr, managedObj);

    Marshal.FreeHGlobal(unmanagedAddr);
    unmanagedAddr = IntPtr.Zero;
}

[править]
Чтобы смоделировать массивы переменной длины, выделите неуправляемую память в структуре и инициализируйте как обычно.*

...