C#调用C/C++动态库,封装各种复杂结构体
C#(6) 
现在公司要做一个使用C#程序调用C++的一个DLL库,解析文件的功能。所以在网上找了一些资料。
一、结构体传递
- #define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数
- typedef struct
- {
- int osVersion;
- int majorVersion;
- int minorVersion;
- int buildNum;
- int platFormId;
- char szVersion[128];
- }OSINFO;
- // 1. 获取版本信息(传递结构体指针)
- JNAAPI bool GetVersionPtr( OSINFO *info );
- // 2.获取版本信息(传递结构体引用)
- JNAAPI bool GetVersionRef(OSINFO &info);
可以通过二种方式进行调用:
- // OSINFO定义
- [StructLayout(LayoutKind.Sequential)]
- public struct OSINFO
- {
- public int osVersion;
- public int majorVersion;
- public int minorVersion;
- public int buildNum;
- public int platFormId;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string szVersion;
- }
1. 方式一(传入结构体引用),在C#中,结构体是以传值方式传递,类才是以传地址方式传递,加关键字ref即可. C端传递了两种不同类型的参数,都可以通过引用来解决.
- [DllImport("jnalib.dll", EntryPoint = "GetVersionPtr")]
- public static extern bool GetVersionPtr(ref OSINFO info);
- public static extern bool GetVersionRef(ref OSINFO info);
2. 方式二(传入IntPtr(平台通用指针))
- IntPtr pv = Marshal.AllocHGlobal(148); //结构体在使用时一定要分配空间(4*sizeof(int)+128)
- Marshal.WriteInt32(pv,148); //向内存块里写入数值
- if (GetVersionPtr(pv)) //直接以非托管内存块地址为参数
- {
- Console.WriteLine("--osVersion:{0}", Marshal.ReadInt32(pv, 0));
- Console.WriteLine("--Major:{0}",Marshal.ReadInt32(pv, 4)); //移动4个字节
- Console.WriteLine("--BuildNum: " + Marshal.ReadInt32(pv, 12));
- Console.WriteLine("--szVersion: "+Marshal.PtrToStringAnsi((IntPtr)(pv.ToInt32()+20)));
- }
- Marshal.FreeHGlobal(pv); //处理完记得释放内存
二.结构体数组的传递
- // 传递结构体指针
- JNAAPI bool GetVersionArray(OSINFO *info,int nLen);
调用:
- /**
- * C#接口,对于包含数组类型,只能传递IntPtr
- */
- [DllImport("jnalib.dll", EntryPoint = "GetVersionArray")]
- public static extern bool GetVersionArray(IntPtr p, int nLen);
- // 源目标参数
- OSINFO[] infos = new OSINFO[2];
- for (int i = 0; i < infos.Length; i++)
- {
- infos[i] = new OSINFO();
- }
- IntPtr[] ptArr = new IntPtr[1];
- ptArr[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO)) * 2); //分配包含两个元素的数组
- IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO)));
- Marshal.Copy(ptArr, 0, pt, 1); //拷贝指针数组
- GetVersionArray(pt, 2); //调用
- //还原成结构体数组
- for (int i = 0; i < 2; i++)
- {
- infos[i]=(OSINFO)Marshal.PtrToStructure((IntPtr)(pt.ToInt32()+i*Marshal.SizeOf(typeof(OSINFO))),typeof(OSINFO));
- Console.WriteLine("OsVersion:{0} szVersion:{1}", infos[i].osVersion, infos[i].szVersion);
- }
三. 复杂结构体的传递
1. 输出参数,结构体作为指针传出
- typedef struct
- {
- char name[20];
- int age;
- double scores[30];
- }Student;
- // Class中包含结构体数组类型
- typedef struct
- {
- int number;
- Student students[50];
- }Class;
- // 传入复杂结构体测试
- JNAAPI int GetClass(Class *pClass,int len);
- // 接口定义
- [DllImport("jnalib.dll", EntryPoint = "GetClass")]
- public static extern int GetClass(IntPtr pv,int len);
- // 结构体定义
- // Student
- [StructLayout(LayoutKind.Sequential)]
- public struct Student
- {
- [MarshalAs(UnmanagedType.ByValTStr,SizeConst=20)]
- public string name;
- public int age;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
- public double[] scores;
- }
- // Class
- [StructLayout(LayoutKind.Sequential)]
- public struct Class
- {
- public int number;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] // 指定数组尺寸
- public Student[] students; // 结构体数组定义
- }
- // 调用复杂结构体测试
- int size = Marshal.SizeOf(typeof(Class)) * 50;
- IntPtr pBuff = Marshal.AllocHGlobal(size); // 直接分配50个元素的空间,比Marshal.copy方便多了
- GetClass(pBuff, 50);
- Class[] pClass = new Class[50];
- for (int i = 0; i < 50; i++)
- {
- IntPtr ptr = new IntPtr(pBuff.ToInt64() + Marshal.SizeOf(typeof(Class)) * i);
- pClass[i] = (Class)Marshal.PtrToStructure(ptr, typeof(Class));
- }
- Marshal.FreeHGlobal(pBuff); // 释放内存
2. 输入参数, 给复杂结构体赋值后作为输入参数传入
对于比较大的结构体指针,无法直接应用结构体类型,转化成IntPtr类型, 此时需要将原生类型转化为指针,并给指针赋值
调用方法: Marshal.StructureToPtr(stu, ptr1, true)
end...
转自:http://tcspecial.iteye.com/blog/1675309
C#调用C/C++动态库,封装各种复杂结构体的更多相关文章
- 关于C#调用非托管动态库方式的性能疑问
最近的项目中,因为一些原因,需要C#调用非托管(这里为C++)的动态库.网上喜闻乐见的方式是采用静态(DllImport)方式进行调用.偶然在园子里看到可以用动态(LoadLibrary,GetPro ...
- C#调用C/C++动态库 封送结构体,结构体数组
一. 结构体的传递 #define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数 typedef struct { int ...
- Android NDK开发及调用标准linux动态库.so文件
源:Android NDK开发及调用标准linux动态库.so文件 预备知识及环境搭建 1.NDK(native development Kit)原生开发工具包,用来快速开发C.C++动态库,并能自动 ...
- linux c编程调用系统的动态库时,要使用dlopen等函数吗?
同问 linux c编程调用系统的动态库时,要使用dlopen等函数吗? 2012-11-27 21:55 提问者: hnwlxyzhl 我来帮他解答 满意回答 2012-12-07 09:08 li ...
- cpp调用c的动态库
目录 cpp调用c的动态库 title: cpp调用c的动态库 date: 2019/11/22 20:34:29 toc: true --- cpp调用c的动态库 CPP文件里这么引用头文件即可 e ...
- C#调用C++动态库方法及动态库封装总结
我只是粗浅的学习过一些C++语法, 变量类型等基础内容, 如有不对的地方还望指出. 如果你跟我一样, 对指针操作不了解, 对封装C++动态库头疼的话, 下面内容还是有帮助的. 转载请注明出处: htt ...
- c++动态库封装及调用(3、windows下动态库调用)
1.DLL的隐式调用 隐式链接采用静态加载的方式,比较简单,需要.h..lib..dll三件套.新建“控制台应用程序”或“空项目”.配置如下: 项目->属性->配置属性->VC++ ...
- c++动态库封装及调用(2、windows下动态库创建)
DLL即动态链接库(Dynamic-Link Libaray)的缩写,相当于Linux下的共享对象.Windows系统中大量采用了DLL机制,甚至内核的结构很大程度依赖与DLL机制.Windows下的 ...
- c++动态库封装及调用(1、动态库介绍)
1.一个程序从源文件编译生成可执行文件的步骤: 预编译 --> 编译 --> 汇编 --> 链接 (1)预编译,即预处理,主要处理在源代码文件中以“#”开始的预编译指令,如宏展开 ...
随机推荐
- ubuntu上配tensorflow
前一阵绕了大弯路,基本弄好了UEFI双系统后,面对的就是CUDA咋装在Linux. 好在教程好多,有些朋友建议先装CUDA再装显卡驱动.弄好之后记录一下详细过程吧. *** 这两天看了一些教程,还是感 ...
- 【模板】多项式乘法 NTT
相对来说是封装好的,可以当模板来用. #include <bits/stdc++.h> #define maxn 5000000 #define G 3 #define ll long l ...
- [codevs3269]混合背包
题目大意:一道混合背包模板. 解题思路:分三种情况讨论,01和完全没什么问题,多重背包需要把物品分成$\log W[i]$件,然后01即可,分成W[i]件01会TLE. 读优大法好! C++ Code ...
- linux 系统相关命令
说明:此篇以 Debian ( ubuntu16.04 ) 命令为例 1. tab键默认是不能自动补全命令 apt install bash-completion // 安装完成之后重启系统 2. 虚 ...
- 【BZOJ 1296】 [SCOI2009]粉刷匠
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] f[i][j][k]表示第i行前j列刷了k次,最大满意度 f[][j][k]=max{f[i][l][k],f[i][l][k-1] ...
- code vs 1216 跳马问题
1216 跳马问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 题目 输入描述 Input Descri ...
- exadata(硬件更换文档部分)
Maintaining Flash Disks Replacing a Flash Disk Due to Flash Disk Failure Each Exadata Storage Server ...
- unity3d 自己主动文件更新系统
游戏内容变更之后.一般而言不会想让玩家下载整个游戏包又一次安装,由于这样会流失大量玩家.全部游戏更新是必须的. 更新的内容包含 数据.资源.代码. 基本原理: 1.将须要更新的文件打包成AssetBu ...
- Linux下安装Mysql(RPM安装)
一.去官网下载本次安装须要的mysql版本号.我们须要安装的是5.1版本号的且centos系统是64位的.所下面载的是MySQL-community-5.1.73-1.rhel5.x86_64.rpm ...
- poj_2828线段树,逆序插入
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...