简体   繁体   English

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

[英]using c lib in c# - struct containing pointer to first element of array

I have to use a C library in C#. 我必须在C#中使用C库。 Here is the part that causes me trouble. 这是导致我麻烦的部分。 The C function with the struct definition : 具有struct定义的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;
};

So the unsigned char * Data_s is a pointer to an array that will contain output data. 因此, unsigned char * Data_s是指向将包含输出数据的数组的指针。 My C# code is below : 我的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;
}

I call it in my program like this 我在程序中这样调用它

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);
}

It simply doesn't work. 它根本不起作用。 When read() function is called a AccessViolationEsception is thrown. 调用read()函数时,将AccessViolationEsception The message is : Attempt to read or write Protected Memory. This is often an indicating that other memory is corrupt. 消息为: Attempt to read or write Protected Memory. This is often an indicating that other memory is corrupt. Attempt to read or write Protected Memory. This is often an indicating that other memory is corrupt.

I tried various things but I really don't know how to handle this... Thanks for the help ! 我尝试了各种方法,但我真的不知道该如何处理...谢谢您的帮助!

First of all you should study the header file of the C library very carefully (I do not have a C header file for the dpc2lib). 首先,您应该非常仔细地研究C库的头文件(我没有dpc2lib的C头文件)。 Please note I based my answer on the SDK documentation found here . 请注意,我的答案基于此处的SDK文档。

Is the read_rb struct really defined with a data alignment on byte boundaries (you have set the Pack member of the StructLayout attribute to 1). 是否在字节边界上以数据对齐方式真正定义了read_rb结构(您已将StructLayout属性的Pack成员设置为1)。 If not you should define the read_rb struct without setting the Pack member: 如果不是,则应在不设置Pack成员的情况下定义read_rb结构:

[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
}

By omitting the Pack member a default value of 0 is used which means that the packing alignment is set to the default for the current platform. 通过省略Pack成员,将使用默认值0,这意味着将当前平台的打包对齐方式设置为默认值。 Furthermore you should define the Data_s member of the read_rb structure as IntPtr . 此外,您应该将read_rb结构的Data_s成员定义为IntPtr

Define the read() function as follows: 定义read()函数,如下所示:

[DllImport("dpc2lib.dll", CallingConvention=CallingConvention.StdCall)]
private static extern ushort read(ushort orderid, ref read_rb request_ptr);

The ref parameter tells the CLR to marshal data in both directions (to native code and back to managed code again). ref参数告诉CLR在两个方向上封送数据(到本机代码,然后再次返回到托管代码)。 Use StdCall as the calling convention because _stdcall is defined in the header file for the read function. 使用StdCall作为调用约定,因为_stdcall是在读取函数的头文件中定义的。

Then, use the read_rb structure and the read() function as follows: 然后,如下使用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);
  }
}

With the help of the Marshal.Copy function you can copy the received data to a managed byte array. 借助Marshal.Copy函数,您可以将接收到的数据复制到托管字节数组中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM