在c#中使用c lib - 包含指向数组第一个元素的指针的struct

时间:2015-01-09 10:06:20

标签: c# c arrays pointers marshalling

我必须在C#中使用C库。这是导致我麻烦的部分。具有结构定义的C函数:

extern "C"__declspec(dllexport)unsigned short _stdcall read(unsigned short orderid, struct read_rb * request_ptr);

struct read_rb
{
   // in
   unsigned long C_Ref;
   unsigned char Slot_Number;
   unsigned char Index;
   // out
   unsigned char Length_s;
   unsigned char * Data_s;
   struct error _error;
};

因此unsigned char * Data_s是一个指向包含输出数据的数组的指针。我的C#代码如下:

[DllImport("dpc2lib.dll")]
private static extern ushort read(ushort orderid, [In, Out] read_rb request_ptr);

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct read_rb
{
    // in
    public uint C_Ref;
    public byte Slot_Number;
    public byte Index;
    // out
    public byte Length_s;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public byte[] Data_s;
    public error _error;
}

我在我的程序中这样称呼它

public float readData(byte slot_Number, byte index, byte data_Length)
{
    read_rb Read_rb = new read_rb();
    byte[] _dataReceived = new byte[5];
    Read_rb.Data_s = _dataReceived;
    int result = read(0, Read_rb);
}

它根本不起作用。当调用read()函数时,抛出AccessViolationEsception。消息是:Attempt to read or write Protected Memory. This is often an indicating that other memory is corrupt.

我尝试了各种各样的东西,但我真的不知道如何处理这个...... 谢谢你的帮助!

1 个答案:

答案 0 :(得分:1)

首先,你应该仔细研究C库的头文件(我没有dpc2lib的C头文件)。请注意,我的答案基于找到的here的SDK文档。

read_rb结构是否真正定义了字节边界上的数据对齐(您已设置Pack成员 的StructLayout属性为1)。如果没有,你应该定义 read_rb结构Pack没有设置[StructLayout(LayoutKind.Sequential)] struct read_rb { public uint C_Ref; // in public byte Slot_Number; // in public byte Index; // in public byte Length_s; // inout public IntPtr Data_s; // out public error error; } [StructLayout(LayoutKind.Sequential)] struct error { ... your error struct members } 成员:

Pack

通过省略Data_s成员,使用默认值0,这意味着 打包对齐设置为当前平台的默认值。 此外,您应该将read_rb结构的IntPtr成员定义为read()

定义[DllImport("dpc2lib.dll", CallingConvention=CallingConvention.StdCall)] private static extern ushort read(ushort orderid, ref read_rb request_ptr); 函数,如下所示:

StdCall

ref参数告诉CLR在两个方向上编组数据(到本机代码并返回到 再次托管代码)。使用_stdcall作为调用约定,因为read_rb已定义 读取函数的头文件。

然后,使用read()结构和const ushort DPC2_DATA_LEN_S = ..; // See SDK documentation and header file read_rb readRb = new read_rb(); readRb.C_Ref = ..; // Set identifier for connection. readRb.Slot_Number = ..; // Set required slot on destination device. readRb.Index = ..; // Set the index parameter. // Set the length field to at least DPC2_DATA_LEN_S // See SDK documentation for more information. readRb.Length_s = DPC2_DATA_LEN_S; try { // Allocate memory for data pointer. readRb.Data_s = Marshal.AllocHGlobal(DPC2_DATA_LEN_S); // Call the read function ushort result = read(ref readRb); // Check return value here. if (result != ../*DPC2_OK*/) { // Handle error case } else { // Use Marshal.Copy to copy the received // data to a byte buffer. byte[] buffer = new byte[DPC2_DATA_LEN_S]; Marshal.Copy(readRb.Data_s, buffer, 0, buffer.Length); // Do something with data ... } } finally { // Finally, release the allocated memory. if(readRb.Data_s !+ IntPtr.Zero) { Marshal.FreeHGlobal(readRb.Data_s); } } 函数,如下所示:

Marshal.Copy

借助{{1}}功能,您可以复制。{ 收到数据到托管字节数组。