C# 调用C++结构体
参考网址:C#调用C/C++动态库,封装各种复杂结构体。_liguo9860的专栏-CSDN博客
现在公司要做一个使用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...
相关文章
- C#调用c++的动态库dll演示例程
- C# http Get/POST请求封装类
- 在VS2015中用C++创建DLL并用C#调用且同时实现对DLL的调试
- C# 获取天气 JSON解析
- vs2019快捷键-小结(C#开发工具Visio studio 2019)
- c# 异步进阶———— paralel [二]
- C# 循环的中断——Break、continue、return
- C# DataGridView的列对象属性探讨 (未完待续)
- C# 将一个对象转换为指定类型
- Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结
- paip.提升用户体验----c++ c# 配色方案
- LibXL 4.0.4 for C++ AND c# Crack
- 编程笔试(解析及代码实现):猴子吃桃。猴子第一天吃了若干个桃子,当即吃了一半,还不解馋,又多吃了一个…的C++、Java、Python、C#等语言代码实现
- Unity 之 C# 利用回调函数实现C++匿名函数
- 解答私信@被c++折磨头秃的花季美少女 //C++ 写一个带命令行参数的程序,可以实现将参数求和、求平均值以及排序之后输出(参数的数量不确定)。
- 从C,C++,JAVA和C#看String库的发展(一)----C语言和C++篇
- c++ 与c#之间的字符串传递
- C#如何对Mongodb进行增删改查
- 重新整理数据结构与算法(c#)—— 图的深度遍历和广度遍历[十一]
- 遇到的C++ cli 转 C++ native 为C# 程序提供接口。
- c++与c#混合编程
- vs2019 实现C#调用c++的dll两种方法
- C#中window窗体和控件