最近因项目需要将一部分代码封装成DLL供其他程序调用,在这个过程中遇到一些困难,现将过程总结出来,供以后参考。
创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站制作、成都做网站、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的康县网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!一、生成DLL生成DLL比较简单,既可以直接新建一个DLL项目:
也可先新建一个空项目,然后在项目属性中设置类型为动态库。
对于需要提供给外部调用的函数,需要在函数前面添加__declspec(dllexport)修饰符:
另外提供一个小技巧,为了不改变工程设置的前提下既能生成DLL又能方便对代码进行调试,可以在Release下配置DLL环境
在Debug下配置调试环境
这样既可不修改任何配置的前提下方便快捷的进行不同环境的切换。
DLL的调用分显式调用和隐式调用,隐式调用需要.h .lib .dll三个文件,需要在项目属性中包含相关路径,显示调用只需要.dll文件,在程序中加载库路径即可,比较灵活。
在知乎上看到一篇文件比较详细,链接如下:
dll显示调用(不需要加载头文件和lib库)
现将内容粘贴如下:
以前看公司封装的库都是头文件和extern “C” 封装,调用需要头文件和lib库,这就需要考虑.h
和lib路径,而且我每次更改接口需要重新再调用工程里面修改头文件,很不方便,我只是在windows开发,ubuntu发布而已。今天才发现windows还有另一种调用方式:显示链接
理论:调用动态DLL有两种方法:一种是隐式链接,一种是显式链接,如果用loadlibrary方式就是显示链接,用.h、.lib、.dll三件套就属于隐式链接。
一:隐式链接:
隐式链接采用静态加载的方式,比较简单,需要.h、.lib、.dll三件套。新建“控制台应用程序”或“空项目”。配置如下:
项目->属性->配置属性->VC++ 目录->在“包含目录”里添加头文件xxx.h所在的目录
项目->属性->配置属性->VC++ 目录->在“库目录”里添加头文件xxx.lib所在的目录
项目->属性->配置属性->链接器->输入->在“附加依赖项”里添加“xxx.lib”(若有多个 lib 则以空格隔开) 。
注:也可以在代码中添加一行设置库的链接,
#pragma comment(lib, “xxx.lib”)
隐式链接和vs加载配置opencv很像,不做实例展示。
二:显式链接:
今天发现,可以用函数指针来调用dll。
调用步骤:
1、声明头文件
,说明我想用windows32方法来加载和卸载DLL 注:如果使用了opencv,不能使用 using namespace cv,可能和windows.h 里面的命名空间冲突,必须使用cv::。(亲自踩坑)
2、然后用typedef定义一个指针函数类型.typedef void(*fun) //这个指针类型,要和你调用的函数类型和参数保持一致
3、定一个句柄实例,用来取DLL的实例地址。HINSTANCE hdll;
格式为hdll=LoadLibrary(“DLL地址”);你封装的dll路径名称
要配置-属性-常规里面把默认字符集“unicode”改成支持多字符扩展。
4、取的地址要判断,定义一个函数指针,用来获取你要用的函数地址。
然后通过Win32 API
函数GetProcAdress来获取函数的地址,参数是DLL的句柄和你要调用的函数名:比如:FUN=(fun)GetProcAdress(hdll,“My_add”);要判断要函数指针是否为空,如果没取到要求的函数,那么要释放句柄。
6、然后通过函数指针来调用函数。
7、调用结束后,就释放句柄FreeLibrary(hdll);
实例展示:
封装:
#include
extern "C" __declspec(dllexport) int My_add(int a,int b) {printf("%d\n",a+b); return a + b; } extern "C" __declspec(dllexport) int My_sub(int a, int b) {printf("%d\n", a - b); return a - b; } ``` 调用: ```c #include #include "Windows.h" typedef int(*Dllfun)(int, int); //using namespace std; //using namespace cv; int main() {Dllfun funName; HINSTANCE hdll; //put DLL under the release path hdll = LoadLibrary(("ThreadLocal.dll")); if (hdll == NULL) {FreeLibrary(hdll); } funName = (Dllfun)GetProcAddress(hdll, "My_add");//My_sub if (funName == NULL) { FreeLibrary(hdll); } int x = 1, y = 10; int z = funName(x, y); printf("z= %d\n", z); FreeLibrary(hdll); return 0; } ``` 自己定义的加法,LoadLibrary GetProcAddress 看起来麻烦,可是省去了头文件和lib的加载,更改接口测试方便,移植到Ubuntu和centeros也方便。
自己亲测有效,代码如下:
#include#includetypedef int(*Dllfun)(void);
using namespace std;
int main()
{while (1)
{Dllfun funName;
HINSTANCE hdll;
//put DLL under the release path
hdll = LoadLibrary("MCU_SMCC1.dll");
if (hdll == NULL)
{ FreeLibrary(hdll);
}
funName = (Dllfun)GetProcAddress(hdll, "Ato_InterfaceFunc");//My_sub
if (funName == NULL)
{ FreeLibrary(hdll);
}
funName();
FreeLibrary(hdll);
}
return 0;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧