操作环境:mac下的win10系统 x64+vs2015+opencv3.0
最近在学习图像,遇到了需要在c++进行动态链接库的设置,因为动态链接库会比静态链接库更加具有效率,故本文尽量从简单的方式记录下这几天的调试经验,以方便自己查阅和同道人学习。
一,动态链接库的创建
1、vs创建win32控制台程序,创建dll文件,并勾选导出符号(出现.h文件)。
2、在设置文件名的头文件中进行导出函数声明:(我的文件名是correct1,所以在correct1.h中进行导出函数声明)
#ifdef CORRECT1_EXPORTS
#define CORRECT1_API __declspec(dllexport)
#else
#define CORRECT1_API __declspec(dllimport)
#endif
//以上均为vs自行生成,代表宏定义,就代表 CORRECT1_API 为输出符号。
#include "stdafx.h"
#include<opencv2/core/core.hpp>//由于用到了opencv,这是opencv的一些文件
#include<opencv2/highgui/highgui.hpp>
using namespace cv;
CORRECT1_API Mat radio(Mat bright);
//导出函数1,CORRECT1_API为导出声明,函数名是radio;函数类型是Mat类型,函数里面定义了一图像矩阵bright。
CORRECT1_API Mat correct2(Mat before, Mat radio1);
//导出函数2,依然是mat类,其中有两个参数,before和radio1
3、进行def模块的声明:
源文件右键–添加–新建项–新建模板def文件。
LIBRARY correct1
EXPORTS
radio @1 //对导出函数1进行标号定义1
correct2 @2 // 对导出函数2进行标号定义2
4、在cpp文件中进行定义函数
CORRECT1_API Mat radio(Mat bright)
//to do sth;
CORRECT1_API Mat correct2(Mat before, Mat radio2)
//to to sth;
5、接下里进行编译,生成lib文件和dll文件。
如果这个时候进行运行程序,是一定会出错的,因为我们设定的是dll文件。
6、这个时候我们进行创建动态链接库的程序都进行完了。我们可以在工程目录下的x64中的debug文件中找到dll文件和lib文件。在后面的调用中会用到这些文件。
二、动态链接库的调用
首先,动态链接库的调用分为静态调用和动态调用。
静态调用需要dll文件,lib文件以及头文件。静态调用虽然理解简单,但每次的机械的操作步骤却并不怎么让人喜欢。由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码,Windows操作系统会负责控制DLL导入内存的次数。这种调用方式简单,能够满足通常的要求。通常采用的方法是把产生动态连接库时产生的.LIB文件(函数入口位置文件)加入到应用程序的工程中,想使用DLL中的函数时,只须在源文件中声明一下。
LIB文件包含了每一个DLL导出函数的符号名和可选择的标识号以及DLL文件名,不含有实际的代码。Lib文件包含的信息进入到生成的应用程序中,被调用的DLL文件会在应用程序加载时同时加载在到内存中。
动态调用只需要dll文件,即显式调用,是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,比较复杂,但能更加有效地使用内存。
由于静态调用方法简单,需要把lib文件加入链接库,然后头文件加入,并且在cpp文件中#include”correct1.h”.并且需要b把创建的dll文件加入工程目录的debug下。然后就可以使用dll中的函数了。但我使用的是动态调用,因为很多时候并没有lib文件,只有别人给的dll文件,所以重点是动态调用。
动态调用是使用window系统中的loadlibrary和GetProcAddress,以及freelibrary函数进行的。
#include "stdafx.h"
#include"iostream"
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
#include<Windows.h>
#include<time.h>
//第一步:为调用的两个导出函数设置类型声明
typedef cv::Mat(*radioFun)(cv::Mat);//类型需与动态链接库里的函数类型一致
typedef cv::Mat(*correct2Fun)(cv::mat,cv::Mat);
int main()
{
HMODULE hDll = LoadLibrary("correct1.dll");//读入动态链接库(需把dll文件放入工程下)
if (hDll != NULL)
{
radioFun radio = (radioFun)GetProcAddress(hDll, MAKEINTRESOURCE(1));//读入函数1的地址
if (radio != NULL)
{
cv::Mat radio1;
radio1 = radio("bright.tif");//直接调用函数
correct2Fun correct = (correct2Fun)GetProcAddress(hDll, MAKEINTRESOURCE(2));//获取函数2(即correct)的地址
//correct(before, radio1);
cv::imshow("radio", radio1);
DWORD start_time = GetTickCount();//测算时间
cv::Mat c = correct("before.tif", radio1);//调用第二个函数
DWORD end_time = GetTickCount();
cv::imshow("before", c);
cout << "The run time is:" << (end_time - start_time) << "ms!" << endl;
cv::waitKey(0);
}
}
FreeLibrary(hDll);//释放库
return 0;
}
由于Windows.h和opencv冲突,所以,只能用CV::Mat来表示。直接运行就OK了、
以后我会慢慢记录自己学到的知识,给自己留个备注,给大家做个参考。
路漫漫其修远兮,吾将上下而求索矣。共勉。