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

标签 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。消息是:尝试读取或写入 protected 内存。这通常表示其他内存已损坏。

我尝试了各种方法,但我真的不知道如何处理... 感谢您的帮助!

最佳答案

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

read_rb 结构是否真的定义了字节边界上的数据对齐(您已经设置了 Pack 成员 StructLayout 属性设置为 1)。如果不是,你应该定义 不设置 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
}

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

定义read()函数如下:

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

ref 参数告诉 CLR 在两个方向(到 native 代码和返回到 托管代码)。使用 StdCall 作为调用约定,因为 _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 函数,您可以复制 接收到的数据到托管字节数组。

关于c# - 在 c# 中使用 c lib - 包含指向数组第一个元素的指针的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27858142/

相关文章:

c - 使用 C libwebsockets 将音频流保存在文件中

c - mikroC 中的浮点到短转换错误

c - 打印从我的链接列表中删除值

c++ - 数组数据未对输出产生正确的计算

arrays - AS3 使默认数组工作 : function example(human:Array = ["heart" ,"skull"])?

c# - 这是正确的实现吗?

c# - Entity Framework 生成的 SQL 查询

c - 如何获取数组最后一个元素的值?

c# - 异常。EntLib 日志中缺少数据信息

c# - 当前不会命中断点 - 远程调试