一. 结构体的传递

#define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数  

typedef struct
{
int osVersion;
int majorVersion;
int minorVersion;
int buildNum;
int platFormId;
char szVersion[];
}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 = )]
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(); //结构体在使用时一定要分配空间(4*sizeof(int)+128)
Marshal.WriteInt32(pv,); //向内存块里写入数值
if (GetVersionPtr(pv)) //直接以非托管内存块地址为参数
{
Console.WriteLine("--osVersion:{0}", Marshal.ReadInt32(pv, ));
Console.WriteLine("--Major:{0}",Marshal.ReadInt32(pv, )); //移动4个字节
Console.WriteLine("--BuildNum: " + Marshal.ReadInt32(pv, ));
Console.WriteLine("--szVersion: "+Marshal.PtrToStringAnsi((IntPtr)(pv.ToInt32()+)));
}
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[];
for (int i = ; i < infos.Length; i++)
{
infos[i] = new OSINFO();
} IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OSINFO)) * 2);
GetVersionArray(pt, ); //调用 //还原成结构体数组
for (int i = ; i < ; i++)
{
IntPtr ptr = (IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(OSINFO)));
infos[i]=(OSINFO)Marshal.PtrToStructure(ptr,typeof(OSINFO));
Console.WriteLine("OsVersion:{0} szVersion:{1}", infos[i].osVersion, infos[i].szVersion);
} Marshal.FreeHGlobal (pt);

三. 复杂结构体的传递

1. 输出参数,结构体作为指针传出

typedef struct
{
char name[];
int age;
double scores[];
}Student; // Class中包含结构体数组类型
typedef struct
{
int number;
Student students[];
}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=)]
public string name;
public int age;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )]
public double[] scores;
} // Class
[StructLayout(LayoutKind.Sequential)]
public struct Class
{
public int number;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = )] // 指定数组尺寸
public Student[] students; // 结构体数组定义
} // 调用复杂结构体测试
int size = Marshal.SizeOf(typeof(Class)) * ;
IntPtr pBuff = Marshal.AllocHGlobal(size); // 直接分配50个元素的空间,比Marshal.copy方便多了
GetClass(pBuff, ); Class[] pClass = new Class[];
for (int i = ; i < ; 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) 

转摘自

  C#调用C/C++动态库 封送结构体,结构体数组

C#调用C/C++动态库 封送结构体,结构体数组的更多相关文章

  1. C#调用C/C++动态库 封送结构体,结构体数组

    因为实验室图像处理的算法都是在OpenCV下写的,还有就是导航的算法也是用C++写的,然后界面部分要求在C#下写,所以不管是Socket通信,还是调用OpenCV的DLL模块,都设计到了C#和C++数 ...

  2. C#调用C/C++动态库,封装各种复杂结构体

    C#调用C/C++动态库,封装各种复杂结构体. 标签: c++结构内存typedefc# 2014-07-05 12:10 6571人阅读 评论(1) 收藏 举报  分类: C(8)  C#(6)  ...

  3. 关于C#调用非托管动态库方式的性能疑问

    最近的项目中,因为一些原因,需要C#调用非托管(这里为C++)的动态库.网上喜闻乐见的方式是采用静态(DllImport)方式进行调用.偶然在园子里看到可以用动态(LoadLibrary,GetPro ...

  4. Android NDK开发及调用标准linux动态库.so文件

    源:Android NDK开发及调用标准linux动态库.so文件 预备知识及环境搭建 1.NDK(native development Kit)原生开发工具包,用来快速开发C.C++动态库,并能自动 ...

  5. linux c编程调用系统的动态库时,要使用dlopen等函数吗?

    同问 linux c编程调用系统的动态库时,要使用dlopen等函数吗? 2012-11-27 21:55 提问者: hnwlxyzhl 我来帮他解答 满意回答 2012-12-07 09:08 li ...

  6. cpp调用c的动态库

    目录 cpp调用c的动态库 title: cpp调用c的动态库 date: 2019/11/22 20:34:29 toc: true --- cpp调用c的动态库 CPP文件里这么引用头文件即可 e ...

  7. C# 调用其他的动态库开发应注意的问题

    1.背景 程序开发语言可以说是五花八门,这就引出了一个新问题 ,不同语言开发的系统进行对接时相关调用的问题. 下面我主要说一下我自己在做接口开发时遇到的问题及解决方法仅供参考,我使用的C#开发进行对接 ...

  8. 浙江省“一卡通”异地就医,C#调用省一卡通动态库

    前言,最近学习调用 浙江省一卡通业务,主要就是调用一个DLL,动态库文件,这个动态库是浙大网新研发的. 借着自学的机会把心得体会都记录下来,方便感兴趣的小伙伴学习与讨论. 内容均系原创,欢迎大家转载分 ...

  9. 关于Android NDK中调用第三方的动态库

    因为最近在整合Android 上RTSP播放器的网络库,因需要调用自己编译的网络库,调用一直出现问题,开始时是直接在Android.mk 中加入LOCAL_SHARED_LIBRARIES := li ...

随机推荐

  1. Access数据库多表连接查询

    第一次在Access中写多表查询,就按照MS数据库中的写法,结果报语法错,原来Access的多表连接查询是不一样的 表A.B.C,A关联B,B关联C,均用ID键关联 一般写法:select * fro ...

  2. js作用域和变量提升

    Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of ...

  3. 【十大经典数据挖掘算法】kNN

    [十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 引言 顶级数据挖掘会议ICDM ...

  4. React Native Changed the World? or Nothing.

    RN是一个awesome的技术, facebook很有想法的团队创造出一项新的技术改变了native开发界. 但是RN本身又疑点重重, RN是为了解决什么问题而存在的? 在诞生了一年后, RN又解决了 ...

  5. Visual Studio 2013 Unit Test Project App.config文件设置方法

    开放中经常会要做单元测试,新的项目又没有单元测试项目,怎么才能搭建一个单元测试项目呢? 下面跟我四步走,如有错误之处,还请指正! 1.添加项目 2.添加配置文件 新建app.config文件,注意不是 ...

  6. 【Tip】如何让引用的dll随附的xml注释文档、pdb调试库等文件不出现在项目输出目录中

    项目输出目录(bin/debug|release)中经常是这个样子: main.exemain.pdb a.dll a.xml b.dll b.pdb b.xml ... 其中xml是同名dll的注释 ...

  7. C# MVC绑定 List<DapperRow>到bootstrap-table列表

    1.Dapper返回List<dynamic>对象 /// <summary> /// 获取候选人推荐的分页数据 /// </summary> /// <pa ...

  8. C#中AppDomain.CurrentDomain.BaseDirectory及各种路径获取方法

    // 获取程序的基目录.System.AppDomain.CurrentDomain.BaseDirectory // 获取模块的完整路径,包含文件名System.Diagnostics.Proces ...

  9. 如何给Ubuntu12.10 安装Vmware Tools

    众所周知在VMware虚拟机中安装好了VMware Tools,才能实现主机与虚拟机之间的文件共享,同时可支持自由拖拽的功能,鼠标也可在虚拟机与主机之前自由移动(而不再用按ctrl+alT释放),而且 ...

  10. 流的文件操作(File)

    一.流的分类: 1.流按照方向分类:分为输入流和输出流,流的操作是相对于内存而言. 输入流的定义:当我们从数据源中将数据读取到内存中就称为输入流,也叫读取流. 输出流的定义:当我们将内存中处理好的数据 ...