我们是否必须长时间无人值守?

时间:2013-05-24 20:18:57

标签: c# mono unmanaged managed primitive-types

我使用的API有这样的东西:

int simpletran(LPSTRUCT req)
{
    printf("%d", req->length);
}

typedef unsigned long ULONG;

typdef struct _st {
  ULONG length;
}STRUCT, *LPSTRUCT;

我的C#版本:

[DllImport(LINUXLIB, CallingConvention=CallingConvention.Cdecl)]
public static extern simpletran(STRUCT req);

class STRUCT
{
  public UInt32 length;
}
STRUCT st = new STRUCT();
st.length = (UInt32)100;
simpletran(st);

当我调用非托管函数时,我得到一些长的负值,如-31245665 !!!

我在Linux机器上使用C#mono。

1 个答案:

答案 0 :(得分:1)

我还没有测试过这些,所以可能需要进行一些更改,但这就是我所看到的。

首先,STRUCT应声明如下:

struct STRUCT
{
    public UInt32 length;
}

请注意,我们已从class更改为struct,以便对象的内存布局已知且与C代码所期望的内容相匹配。

<强>更新

经过一些进一步的考虑之后,有一种更简单的方式来声明和调用方法,我将在下面留下原始答案,以便采用另一种方式。

您的P / Invoke签名应为:

[DllImport(LINUXLIB, CallingConvention=CallingConvention.Cdecl)]
public static extern int simpletran(ref STRUCT req);

请注意,我们已将STRUCT更改为ref STRUCT,因为STRUCT是值类型,而C代码需要指向该结构的指针。

你会这样称呼它:

STRUCT st = new STRUCT();
st.length = (UInt32)100;
simpletran(ref st);

<强>原始

[DllImport(LINUXLIB, CallingConvention=CallingConvention.Cdecl)]
public static extern int simpletran(IntPtr req);

请注意,我们已将STRUCT更改为IntPtr,因为STRUCT必须是值类型,而C代码需要指向该结构的指针。

你会这样称呼它:

STRUCT st = new STRUCT();
st.length = (UInt32)100;
IntPtr ptr = Marshal.AllocHGlobal(sizeof(STRUCT));
Marshal.StructureToPtr(st, ptr, false);
simpletran(ptr);
Marshal.FreeHGlobal(ptr);

在创建实例和调用分配一大块非托管内存的方法之间添加额外的步骤,以便在(Marshal.AllocHGlobal)中存储结构的值,并将st的值复制到其中内存Marshal.StructureToPtr(...)。通过拨打Marshal.FreeHGlobal

,请务必在通话后释放分配的内存