如何将原生C ++内存转换为C#结构?

时间:2011-10-03 10:30:17

标签: c# interop pinvoke

我在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;
};

我需要在C#代码中调用func1并传递Rect

我执行以下操作:

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

func1(???, rectSize);

???应该传递rect的位置放置什么(但由于类型不兼容而无法实现)?

似乎应该传递IntPtr,然后转换为struct rect。怎么做到这一点?

(此处为rect输出参数)

更新

希望不要更改C ++代码和C#包装器的签名 - 它是第三部分代码 此外,Rect传递为func1

的第一个参数并不总是变量

3 个答案:

答案 0 :(得分:3)

您更改了游戏规则以禁止修改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 :(得分:1)

使用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)));

答案 2 :(得分:1)

尝试传递ref Rect。

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