我必须在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.
我尝试了各种各样的东西,但我真的不知道如何处理这个...... 谢谢你的帮助!
答案 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}}功能,您可以复制。{ 收到数据到托管字节数组。