基于C#调用c++Dll结构体数组指针的问题详解
作者:jadeflute 发布时间:2021-12-10 23:16:41
标签:C#,调用,c++,Dll,结构体,数组,指针
C#调用c++dll文件是一件很麻烦的事情,首先面临的是数据类型转换的问题,相信经常做c#开发的都和我一样把学校的那点c++底子都忘光了吧(语言特性类)。
网上有一大堆得转换对应表,也有一大堆的转换实例,但是都没有强调一个更重要的问题,就是c#数据类型和c++数据类型占内存长度的对应关系。
如果dll文件中只包含一些基础类型,那这个问题可能可以被忽略,但是如果是组合类型(这个叫法也许不妥),如结构体、类类型等,在其中的成员变量的长度的申明正确与否将决定你对dll文件调用的成败。
如有以下代码,其实不是dll文件的源码,而是厂商给的c++例子代码
c++中的结构体申明
typedef struct
{
unsigned char Port;
unsigned long Id;
unsigned char Ctrl;
unsigned char pData[8];
}HSCAN_MSG;
c++中的函数申明(一个c++程序引用另一个c++的dll文件)
extern "C" int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);
c++中的调用:
....
HSCAN_MSG msg[100];
.....
HSCAN_SendCANMessage(m_nDevice,m_nPort,msg,nFrames);
由上述代码可见,msg是个结构体的数组。
下面是我的c#的代码
c#结构体申明:(申明成)
[StructLayout(LayoutKind.Sequential)]
public struct HSCAN_MSG
{
// UnmanagedType.ByValArray, [MarshalAs(UnmanagedType.U1)]这个非常重要,就是申明对应类型和长度的
[MarshalAs(UnmanagedType.U1)]
public byte Port;
[MarshalAs(UnmanagedType.U4)]
public uint nId;
[MarshalAs(UnmanagedType.U1)]
public byte nCtrl;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] pData;
};
c#函数申明
[DllImport("HS2106API.dll")]
public static extern int HSCAN_SendCANMessage(
byte nDevice, byte nPort, HSCAN_MSG[] pMsg, int nLength);
C#函数调用
HSCAN_MSG[] msg = new HSCAN_MSG[1]; //发送缓冲区大小可根据需要设置;
for (int yy = 0; yy < msg.Length; yy++)
{
msg[yy] = new HSCAN_MSG();
}
//...结构体中的成员的实例化略
HSCAN_SendCANMessage(0x0, 0x0, msg, 1)
那些只能用指针不能用结构体和类的地方
c++中的结构体申明
typedef struct
{
unsigned char Port;
unsigned long Id;
unsigned char Ctrl;
unsigned char pData[8];
}HSCAN_MSG;
c++中的函数申明(一个c++程序引用另一个c++的dll文件)
extern "C" int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);
c#中的结构体申明:
[StructLayout(LayoutKind.Sequential)]
public struct HSCAN_MSG
{
[MarshalAs(UnmanagedType.U1)]
public byte Port;
/// <summary>
/// 节点标识,nEFF=1 时(扩展帧),为29 位nEFF=0(标准帧)时,为11 位;
/// </summary>
[MarshalAs(UnmanagedType.U4)]
public uint nId;
[MarshalAs(UnmanagedType.U1)]
public byte nCtrl;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] pData;
};
c#函数的调用:包含使用指针IntPtr替代结构体数组和读取IntPtr的方法
HSCAN_MSG[] msg1 = new HSCAN_MSG[10];
for (int i = 0; i < msg1.Length; i++)
{
msg1[i] = new HSCAN_MSG();
msg1[i].pData = new byte[8];
}
IntPtr[] ptArray = new IntPtr[1];
ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);
IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));
Marshal.Copy(ptArray, 0, pt, 1);
int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);
textBoxStatus.Text += "/r/n" + "读取0口:" + count.ToString() + "帧数据";
for (int j = 0; j < 10; j++)
{
msg1[j] =
(HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))
, typeof(HSCAN_MSG));
textBoxStatus.Text += "/r/n收到0口" + Convert.ToByte(msg1[j].pData[0]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[1]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[2]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[3]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[4]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[5]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[6]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[7]).ToString();
}
来源:http://blog.csdn.net/wumuzhizi/article/details/48180167


猜你喜欢
- @ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的
- Android getevent用法实例详解最近在测试设备按键的常用命令,感觉这些命令都有的,但就是不知道怎么查找。翻阅了几篇博
- 1、运算符两边的变量为boolean变量时 先列出代码:public clas
- 就网络和应用程序而言,键盘快捷键很重要,今天我们要谈的便是让这类快捷键得以在Flutter运作的小部件:Focus、Shortcuts和Ac
- C#判断数据类型的简单示例代码:int i = 5; Console
- 前言:仿微信通讯录搜索功能,通过汉字或拼音首字母找到匹配的联系人并显示匹配的位置一:先看效果图字母索引搜索匹配二:功能分析1:汉字转拼音通讯
- 1.问题产生情况我遇到这个问题是做微信开发的时候有些有用的头像用了微信的emoji表情,然而我的mysql数据库用的编码是utf8_gene
- 目前为止我们已经了解了如何通过编程创建 CompletableFuture 对象以及如何获取返回值,虽然看起来这些操作已经比较方便,但还有进
- 线索二叉树的意义对于一个有n个节点的二叉树,每个节点有指向左右孩子的指针域。其中会出现n+ 1个空指针域,这些空间不储存任何事物,浪费着内存
- 一、前言在一些对高并发请求有限制的系统或者功能里,比如说秒杀活动,或者一些网站返回的当前用户过多,请稍后尝试。这些都是通过对同一时刻请求数量
- 本文实例为大家分享了Java Socket实现多人聊天系统的具体代码,供大家参考,具体内容如下前言GitHub地址开发环境:Eclipse
- 如题,在GitHub上找了一圈想找一个MongoDB的的ORM框架,未偿所愿,就去翻了翻官网(https://docs.mongodb.co
- 大多数情况下你不需要访问者模式,但当一旦需要访问者模式时,那就是真的需要它了,这是设计模式创始人的原话。可以看出应用场景比较少,但需要它的时
- Feign多参数传递及注意的问题这边沿用前面的Eureka,Feign,Service在服务提供者cloud-shop-userservic
- SpringMVC中的 * 用于拦截控制器方法的执行,执行在Controller前后,和视图渲染完成后。如下图所示:一、创建 * 继承Han
- 在项目中常常常使用到DataTable,假设DataTable使用得当,不仅能使程序简洁有用,并且可以提高性能,达到事半功倍的效果,List
- 前言:什么是多数据源?最常见的单一应用中最多涉及到一个数据库,即是一个数据源(Datasource)。那么顾名思义,多数据源就是在一个单一应
- 1. Java中程序的逻辑控制语句1.1顺序结构顺序结构比较简单,按照代码书写的顺序一行一行执行1.2分支结构1.2.1 switch语句这
- JAVA是面向对象的语言,开发者在操作数据的时候,通常更习惯面对一个特定类型的对象,如一个用户就是一个User类的对象。DAO层需要做的,就
- 最近参与了开发一款旅行APP,其中包含实时聊天和动态评论功能,终于耗时几个月几个伙伴完成了,今天就小结一下至于实时聊天功能如果用户不多的情况