在 c# 中使用 c lib - 包含指向数组第一个元素的指针的结构
using c lib in c# - struct containing pointer to first element of array
我必须在 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.
我尝试了各种方法,但我真的不知道如何处理...
感谢您的帮助!
首先你应该仔细研究C库的头文件(我没有dpc2lib的C头文件)。请注意,我的回答基于找到的 SDK 文档 here.
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
成员,使用默认值 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 在两个方向(到本机代码和返回到
托管代码)。使用 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 函数:
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.
我尝试了各种方法,但我真的不知道如何处理... 感谢您的帮助!
首先你应该仔细研究C库的头文件(我没有dpc2lib的C头文件)。请注意,我的回答基于找到的 SDK 文档 here.
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
成员,使用默认值 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 在两个方向(到本机代码和返回到
托管代码)。使用 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
函数,您可以复制
接收到的数据到托管字节数组。