Как преобразовать нативную память C ++ в структуру C #? - PullRequest
7 голосов
/ 03 октября 2011

У меня есть следующий нативный интерфейс функции в C ++:

int func1(void* param, int sizeOfParam).

В документации приведен следующий пример вызова:

typedef struct
{
    int x;
    int y;
    int width;
    int height;
} Rect;

Rect rect;

int func1((void*)&rect, sizeof(rect));

Мне нужно вызвать эту функцию из кода C #.

У меня есть следующий заголовок в C # от разработчиков родной библиотеки:

[DllImport(NATIVE_DLL_NAME, 
 CallingConvention = CallingConvention.Cdecl, 
 EntryPoint = "func1")]
private static extern int func1(IntPtr param, int sizeOfParam);

У меня также есть следующая структура C # Rect:

public struct Rect
{
    int x;
    int y;
    int width;
    int height;
};

Мне нужно позвонить func1 в коде C # и передать Rect:

Я делаю следующее:

Rect rect = new Rect();
int rectSize = System.Runtime.InteropServices.Marshal.SizeOf(rect);

func1(???, rectSize);

Что поместить в позицию ???, где следует передать rect (но это невозможно из-за несовместимых типов)?

Кажется, что IntPtr должно быть передано и затем преобразовано в struct rect Как этого добиться?

(rect здесь является выходным параметром)

UPDATE:

Желательно не менять подписи кода C ++ и оболочек C # - это код третьей части.
Более того, не всегда переменная Rect передается как первый параметр func1

Ответы [ 3 ]

3 голосов
/ 03 октября 2011

Вы изменили правила игры, чтобы запретить модификации кода C #. И поэтому P / invoke должен иметь такую ​​форму:

private static extern int func1(IntPtr param, int sizeOfParam);

В этом случае вам нужно выполнить сортировку вручную:

int size = Marshal.SizeOf(typeof(Rect));
IntPtr param1 = Marshal.AllocHGlobal(size);
try
{
    func1(param1, size);
    Rect rect = (Rect)Marshal.PtrToStructure(param1, typeof(Rect));
}
finally
{
    Marshal.FreeHGlobal(param1);
}
1 голос
/ 03 октября 2011

Попробуйте вместо этого передать ref Rect.

[DllImport(NATIVE_DLL_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "func1")]
private static extern int func1(ref Rect param, int sizeOfParam);
1 голос
/ 03 октября 2011

Я бы, вероятно, немного облегчил себе жизнь, используя out параметр типа Rect вместо IntPtr Как это:

[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
    int x;
    int y;
    int width;
    int height;
};

[DllImport(NATIVE_DLL_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "func1")]
private static extern int func1(out Rect param, int sizeOfParam);

Затем для вызова функции вы можете написать это:

Rect param;
int res = func1(out param, Marshal.SizeOf(typeof(Rect)));
...