C#调用DLL复杂函数结构体
2017-11-26 11:32
543 查看
现在公司要做一个使用C#程序调用C++的一个DLL库,解析文件的功能。所以在网上找了一些资料。
一、结构体传递
[cpp]
view plain
copy
print?
#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);
可以通过二种方式进行调用:
[csharp]
view plain
copy
print?
// 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端传递了两种不同类型的参数,都可以通过引用来解决.
[csharp]
view plain
copy
print?
[DllImport("jnalib.dll", EntryPoint = "GetVersionPtr")]
public static extern bool GetVersionPtr(ref OSINFO info);
public static extern bool GetVersionRef(ref OSINFO info);
2. 方式二(传入IntPtr(平台通用指针))
[csharp]
view plain
copy
print?
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); //处理完记得释放内存
二.结构体数组的传递
[cpp]
view plain
copy
print?
// 传递结构体指针
JNAAPI bool GetVersionArray(OSINFO *info,int nLen);
调用:
[csharp]
view plain
copy
print?
/**
* 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. 输出参数,结构体作为指针传出
[cpp]
view plain
copy
print?
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);
[csharp]
view plain
copy
print?
// 接口定义
[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
一、结构体传递
[cpp]
view plain
copy
print?
#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);
#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);
可以通过二种方式进行调用:
[csharp]
view plain
copy
print?
// 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;
}
// 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端传递了两种不同类型的参数,都可以通过引用来解决.
[csharp]
view plain
copy
print?
[DllImport("jnalib.dll", EntryPoint = "GetVersionPtr")]
public static extern bool GetVersionPtr(ref OSINFO info);
public static extern bool GetVersionRef(ref OSINFO info);
[DllImport("jnalib.dll", EntryPoint = "GetVersionPtr")] public static extern bool GetVersionPtr(ref OSINFO info); public static extern bool GetVersionRef(ref OSINFO info);
2. 方式二(传入IntPtr(平台通用指针))
[csharp]
view plain
copy
print?
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); //处理完记得释放内存
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); //处理完记得释放内存
二.结构体数组的传递
[cpp]
view plain
copy
print?
// 传递结构体指针
JNAAPI bool GetVersionArray(OSINFO *info,int nLen);
// 传递结构体指针 JNAAPI bool GetVersionArray(OSINFO *info,int nLen);
调用:
[csharp]
view plain
copy
print?
/**
* 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);
}
/** * 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. 输出参数,结构体作为指针传出
[cpp]
view plain
copy
print?
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);
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);
[csharp]
view plain
copy
print?
// 接口定义
[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); // 释放内存
// 接口定义 [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
相关文章推荐
- C#调用VC的DLL的接口函数参数类型转换一览表
- 如何生成DLL文件并导出函数及如何在C++或C#中调用DLL中导出的函数
- (转)C#调用dll中的函数
- C#调用VC DLL接口函数参数类型转换的方法
- C#动态调用DLL中的函数
- C# 调用 C++ dll 函数 时传递字符串 需要注意的问题(zz)
- 在C#里面调用带有回调函数和自定义结构体的DLL的例程
- C#调用VC的DLL的接口函数参数类型转换一览表
- C#与DLL和COM的混合编程(1)-C#调用C++写的非托管的DLL中导出的函数
- C#调用VC DLL接口函数参数类型转换方法介绍
- C# 调用 C++ dll 函数 时传递字符串 需要注意的问题
- 在 C# 中动态调用 native dll 的导出函数
- C#加载dll(动态链接库)并调用其函数
- C#调用VC DLL接口函数参数类型对应介绍
- C#中加载dll并调用其函数的实现方法
- C# 调用带有复杂参数的C++ ,delphi dll 注意事项备注。(C++ dll 怎么回调C# 程序,参数怎么写?)
- string类型函数 bcb做dll,c#调用
- C#调用C dll,结构体传参
- C#调用VC DLL接口函数参数类型转换方法介绍
- C#调用C++的dll关于复杂结构的参数传递