找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2957|回复: 12

C#调用C++动态链接库及类库详解

 火.. [复制链接]
  • 打卡等级:常驻代表
  • 打卡总天数:34
  • 打卡月天数:6
  • 打卡总奖励:9027
  • 最近打卡:2025-12-17 23:15:51

2823

主题

541

回帖

2万

积分

管理员

积分
22569
发表于 2021-1-11 20:39:51 | 显示全部楼层 |阅读模式
来源:编程手札(头条)动态链接库
动态链接库全称Dynamic Link Library(简称DLL),通常是由一组实现某种特定功能的函数集合。它包含了该功能的具体实现方法和资源,通过编译生成一个后缀为DLL的文件供应用程序或者其他dll调用。用户不需要知道功能的具体实现过程,只需要根据DLL提供的API正确传参就可以得到想要的结果。


DLL的优点
DLL只有在被调用的时候才需要分配内存而且多个进程可以同时使用一个 DLL,在内存中共享该 DLL 的一个副本可以大大节省内存和减少交换操作。DLL可以使用多种编程语言编写,只要程序遵循函数的调用约定就可以被其他编程语言所调用,大大提高了代码复用性和拓展性。当DLL中的函数发生更改时只要函数的参数和返回值没有更改,就无需重新编译调用的应用程序,有助于应用程序的升级和优化等。


​C++编写DLL
在写Fanuc开发的时候我就喜欢把fanuc操作的所有功能编写成一个动态链接库,具体的实现方法可以参考专栏中的文章【C/C++实战023:动态类库的开发详解】。
专栏

C/C++实战系列
作者:编程手札
19.9币
14人已购

查看




这里要说的重点是该DLL在头文件中直接声明了成员方法,使用extern "C" __declspec(dllexport)标记将其直接导出。


​C#调用C++DLL
这类DLL在C#中采用[DLLImport(“DLL文件路径”)]特性标记方式来调用DLL中的函数 ,利用extern修饰符声明该DLL支持在外部实现的方法。这里需要注意参数的类型,声明之后就可以直接在C#编程中使用这个方法了。
[DllImport("FANUC_API.dll", SetLastError = true, EntryPoint = "Connect")]public static extern string Connect(byte[] ip, int port=8193, long timeout=2);C++编写类库
类库就是实现各种功能方法的集合,当项目比较大的时候我们会把功能分的更细,这时候我们就会用到类库。将一些常用的编程任务(包括诸如字符串处理、数据格式转换、数据库连接以及文件访问等)封装成类库,方便在开发中直接使用类库封装的方法快速实现功能需求以提高开发效率!我在NX二次开发的时候就会把具体的功能进行类库封装,里面包含了该功能实现所以的成员方法和成员属性。


​C#调用C++类库
这里需要注意的是C#属于托管型代码而C++是非托管型代码,托管型代码的对象在托管堆上分配内存而非托管型代码对象有实际的内存地址,所以C#不能直接调用C++类库中的类。要实现C#调用C++类库要么将C++类库改成托管型C++dll库,要么就通过另一个C++动态链接库将要调用的类成员方法导出。


​托管型C++类库
修改之前写好的类库,在编写动态链接库时通过项目属性->高级->公共语言运行时支持,将默认“无公共语言运行时支持”改成“公共语言运行时支持(/clr)”。此时我们新建一个C#的控制台程序来测试,引用刚生成的DLL文件(默认无公共语言运行时支持的DLL无法被C#引用)并在Main函数中实例化该类。


​C++定义托管类
这时你会发现代码提示:“EDIT”不可访问,因为它具有一定的保护级别,这时我们需要为动态链接库中的class类添加public将其设置为公有类,允许通过类的实例变量进行访问。并利用ref创建托管类对象,这时候就不能再用extern "C" __declspec(dllexport)标记将导出了(该方式不适用于托管类型) ,这里我们设定编译器的状态指令为#pragma once(保证头文件被编译一次)。#pragma指令在保持与C和C++语言完全兼容的情况下,为编译器提供主机或操作系统专有的特征。


C#调用C++类库
​这时候我们在C#控制台中就可以通过实例化该类来调用其成员方法,这里我们可以发现原函数中的char*类型参数在C#调用后提示参数类型为sbyte*类型。这是因为C++和C#之间使用不同数据类型,所以当C#调用C++编写的类库时就需要转换数据类型。不过C++的char*对应C#不应该是byte[]么,怎么变成sbyte*了(第一次见)?为了传参我需要将string类型先转成sbyte[]类型,再通过fixed将sbyte[]类型转成sbyte*类型。这说明该方法引用的类存在不安全隐患,容易导致内存泄露。


非托管型C++类库
还有一种方式就是创建一个新的C++动态链接库,这个动态链接库专门用来调用类库中的成员方法并将其导出。在方法中实例化类通过公共方法间接调用类成员方法并将其暴露出去,这样C#就可以直接通过[DLLImport(“DLL文件路径”)]特性标记方式来调用DLL中的函数了。


总结:
从上面的调用来看C++定义托管型类库会存在安全隐患而且还不适应其他语言调用,所以还是建议用标准的C++库。利用一个导出库将所有类库中的成员方法暴露出去,像UG等大型大软件都是这样来操作的。以上内容是小编给大家分享的【C#实战050:C#调用C++动态链接库及类库详解】,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
工控课堂 www.gkket.com

0

主题

192

回帖

685

积分

中级会员

积分
685
发表于 2021-1-12 04:15:17 | 显示全部楼层
激动人心,无法言表!
工控课堂 www.gkket.com

0

主题

87

回帖

277

积分

注册会员

积分
277
发表于 2021-1-12 04:15:24 | 显示全部楼层
楼主您的技术水准,我最服你,其他都是浮云
工控课堂 www.gkket.com

0

主题

466

回帖

2545

积分

高级会员

积分
2545
发表于 2025-11-12 09:30:18 | 显示全部楼层
这波分析到位,逻辑满分!
工控课堂 www.gkket.com

0

主题

88

回帖

132

积分

新手上路

积分
132
发表于 2025-11-12 09:54:31 | 显示全部楼层
原来还有这种操作,长见识了!
工控课堂 www.gkket.com

0

主题

87

回帖

161

积分

新手上路

积分
161
发表于 2025-11-12 10:20:29 | 显示全部楼层
路过混个脸熟,顺便为优质内容打 call~
工控课堂 www.gkket.com

0

主题

57

回帖

64

积分

新手上路

积分
64
发表于 2025-11-17 22:07:11 | 显示全部楼层
同款经历!简直是世另我
工控课堂 www.gkket.com

0

主题

101

回帖

155

积分

新手上路

积分
155
发表于 2025-11-17 22:11:49 | 显示全部楼层
求个链接 / 教程,楼主好人一生平安~
工控课堂 www.gkket.com

0

主题

78

回帖

119

积分

新手上路

积分
119
发表于 2025-11-17 22:12:37 | 显示全部楼层
学到了学到了,这波分享太实用啦!
工控课堂 www.gkket.com

0

主题

102

回帖

153

积分

新手上路

积分
153
发表于 2025-11-17 22:17:28 | 显示全部楼层
救命!这回复笑到我捶桌,必须置顶~
工控课堂 www.gkket.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|手机版|免责声明|本站介绍|工控课堂 ( 沪ICP备20008691号-1 )

GMT+8, 2025-12-22 20:58 , Processed in 0.146877 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表