#include "devicecontrol.h" #include "yhplugin.h" static YHPlugin plugin; void setServer(const char *hostName, int port) { plugin.setServer(hostName, port); }
#ifndef DEVICECONTROL_H #define DEVICECONTROL_H #if defined YHPLUGIN_LIBRARY #define DLLSHARED_EXPORT __declspec(dllexport) #else #define DLLSHARED_EXPORT __declspec(dllimport) #endif #ifdef _STDCALL_SUPPORTED #define APICALL __stdcall #else #define APICALL __cdecl //用来控制函数是否重命名,cdecl不需要重命名 #endif //这一层是给上层接口层 extern "C" { DLLSHARED_EXPORT void APICALL setServer(const char* hostName, int port); } #endif // DEVICECONTROL_H
最近收到的新需求,需要提供给上层一个库文件,库文件本身只是用来发送特定报文给下层,通过Tcp协议。
因为我们使用的框架是Qt的,所以库文件里面用到了Qt的网络通信(network),使用QTcpSock等模块。
但是不清楚上层到底用的什么架构,如果一样是Qt的架构那么Qt的默认生成库也就OK;但是如果是其他的环境那么不一定可以。
所以最后决定将这个deviceControl库做成C/C++都可以用的形式。
由于基础差,查了一些资料才搞懂了库的一些概念和规则。
这里贴出几个很好的帖子大家可以一起学习(超链接好像没有加成功):
https://blog.csdn.net/dongchongyang/article/details/52926310
https://blog.csdn.net/leehong2005/article/details/8607536
https://www.qter.org/forum.php?mod=viewthread&tid=20439
在此抄录一段很关键的段落:
dll中的函数在被调用时是以函数名或函数编号的方式被索引的。这就意味着采用某编译器的C++的Name-Mangling方式产生的dll文件可能不通用。因为它们的函数名重命名方式不同。为了使得dll可以通用些,很多时候都要使用C的Name-Mangling方式,即是对每一个导出函数声明为extern “C”,而且采用_stdcall调用约定,接着还需要对导出函数进行重命名,以便导出不加修饰的函数名。
注意到extern “C”的作用是为了解决函数符号名的问题,这对于动态链接库的制造者和动态链接库的使用者都需要遵守的规则。
动态链接库的显式装入就是通过GetProcAddress函数,依据动态链接库句柄和函数名,获取函数地址。因为GetProcAddress仅是操作系统相关,可能会操作各种各样的编译器产生的dll,它的参数里的函数名是原原本本的函数名,没有任何修饰,所以一般情况下需要确保dll’里的函数名是原始的函数名。分两步:一,如果导出函数使用了extern”C” _cdecl,那么就不需要再重命名了,这个时候dll里的名字就是原始名字;如果使用了extern”C” _stdcall,这时候dll中的函数名被修饰了,就需要重命名。二、重命名的方式有两种,要么使用*.def文件,在文件外修正,要么使用#pragma,在代码里给函数别名。
封装的壳在最上面。想吐槽一下这个编辑功能越来越难用了,代码增加不是在光标位置而是在顶端;随笔的一些选项控件也不好用。
原文地址:https://www.cnblogs.com/warmSnowFY/p/12421571.html