将C结构编组为C#

Que*_*ueg 8 .net c# dll pinvoke interop

假设我有一个结构:

typedef struct {
float x;
float y;
float z;
int   ID;
} Vertex;
Run Code Online (Sandbox Code Playgroud)

和一个C++函数:

float first(Vertex* ptr, int length){ //really silly function, just an example
    Vertex u,v;
    u.x = ptr[0].x; //...and so on, copy x,y,z,ID
    v.x = ptr[1].x; 
    return (u.x * v.x + u.y * v.y + u.z * v.z);
    }


Vertex* another(float a, int desired_size){
    Vertex v = (Vertex*)malloc(desired_size*sizeof(Vertex));
    v[0].x = a;
    v[1].x = -a; //..and so on.. make some Vertices.
    return v;
}
Run Code Online (Sandbox Code Playgroud)

首先 - 我的IDE.我正在使用Visual Studio 2010,构建一个C#(4.0)应用程序; C++部分也是在VS2010中构建的.

我知道如何构建一个C/C++代码的DLL并在C#应用程序中使用它,但直到今天我只使用原始参数并返回如下值:

    [DllImport("library.dll", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern int simple(int a, int b);
Run Code Online (Sandbox Code Playgroud)

今天我需要通过一个阵列的结构(如在上面的例子)..也许还接收一回..

如何将C#类"翻译"为C结构(反之亦然)?

Dav*_*nan 9

结构可以像这样声明:

[StructLayout(LayoutKind.Sequential)]
public struct Vertex {
    public float x;
    public float y;
    public float z;
    public int ID;
}
Run Code Online (Sandbox Code Playgroud)

接下来,您需要确定一个调用约定.几乎可以肯定你的C++代码编译cdecl.让我们坚持下去.

该函数首先很容易从C#调用:

[DllImport("library.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern float first(Vertex[] vertices);
Run Code Online (Sandbox Code Playgroud)

请注意,您不应该SetLastError在这里使用- 那是Windows API函数.而且没有必要设置,CharSet因为这里没有文字.


现在,another事情变得更加复杂.如果您可以在C#代码中分配内存,那么这绝对是可行的方法.

void PopulateVertices(Vertex *vertices, int count)
{
    for (int i=0; i<count; i++)
    {
        vertices[i].x = ....
    }
}
Run Code Online (Sandbox Code Playgroud)

在C#端你声明它是这样的:

[DllImport("library.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void PopulateVertices(Vertex[] vertices, int count);
Run Code Online (Sandbox Code Playgroud)

并称之为这样

Vertex[] vertices = new Vertex[2];
PopulateVertices(vertices, vertices.Length);
Run Code Online (Sandbox Code Playgroud)

如果你不想在围栏的C#侧分配,那么就这样做:

  1. 从C++代码返回一个指针并分配它CoTaskMemAlloc.
  2. 在C#中声明导入函数的返回值为IntPtr.
  3. 使用Marshal.PtrToStructure和一些指针算法将返回数组封送到C#数组中.
  4. 调用Marshal.FreeCoTaskMem释放本机模块中分配的内存.

但是,如果您需要我的建议,请尝试坚持在托管代码中分配数组.

  • 在结构体的C#中将其声明为“ float [] info;”,并使用以下属性进行标记:`[[MarshalAs(UnmanagedType.ByValArray,SizeConst = 3)]`在此处阅读有关UnmanagedType属性的全部信息:http://msdn.microsoft .com / zh-CN / library / system.runtime.interopservices.unmanagedtype.aspx (2认同)