三.动态链接库的使用方法
静态链接库存在很多问题,那么动态链接库就能很好地解决静态链接库的问题。
. exe在可执行程序中没有相应库的代码,当软件运行起来再把库代码拷到内存。
1.dll文件创建
我们在visual studio中创建动态链接库:
在创建完成后我习惯将多余的文件全部删除,新增自己需要的文件:
MyDll.h文件:
#pragma once _declspec(dllexport) int Plus(int x, int y); _declspec(dllexport) int Sub(int x, int y); _declspec(dllexport) int Mul(int x, int y); _declspec(dllexport) int Div(int x, int y);
MyDll.cpp文件:
#include "MyDll.h" int Plus(int x, int y) { return x + y; } int Sub(int x, int y) { return x - y; } int Mul(int x, int y) { return x * y; } int Div(int x, int y) { return x / y; }
跟创建.lib文件后一样点击平时的编译运行按钮,提示无法运行(本来就无法单独运行),但已成功生成.dll 文件,去到 Debug 或 Release 目录下即可看到,注意同样还有个.lib文件,我们后面会用到。
.dll文件调用
1.隐式调用:
首先,我们将前面创建好的.lib文件和.dll文件放入项目目录下面(静态链接库函数是放在.lib文件中的,但是动态链接库的.lib文件中,可以理解为只放了函数在哪里,而真正的函数是放在.dll文件中的。
完成之后,添加代码:
#pragma comment(lib,"dll名.lib");
然后加入函数声明:
extern "C" _declspec(dllexport) int Plus(int x, int y);
这里解释一下该代码:
extren “C”表示这是个全局函数,可以供各个其他函数调用。
“C”表示按照C语言的方式进行编译和链接,那么我们为什么要用C语言的方式进行编译呢?原因是C++函数重载,编译器为了避免出现函数名一样的函数,会将我们写好的函数名进行更改,而使用C语言方式进行编译后就不会更改我们的函数名了。
_declspec(dllexport)是告诉编译器,此函数为导出函数。
2.显式调用:
1.定义函数指针:
typedef int (_stdcall *Plus)(int,int);
2.声明函数指针变量:
lpPlus myPlus;
3.动态加载dll到内存中
HINSTANCE HModule=LoadLibrary("DllName.dll");
4.获取函数地址:
myPlus=(lpPlus)GetProAddress(hModule,"_Plus@8");
5.调用函数:
int a=myPlus(1,2);
特别说明:
1.Handle代表系统的内核对象,如文件句柄,线程句柄,进程句柄
2.HMODULE是代表程序载入的模块
3.HINSTANCE在Win32下与HMODULE是相同的东西,Win16一六
4.HWND是窗口句柄
实际上,这些都是无符号的整形,Windows之所以这样设计,主要有两个目的:
1.方便区分
2.避免使用者误进行运算
动态调用主要通过 LoadLibrary 获取 加载dll 并获取其地址,后通过 GetProcAddress 通过 dll 句柄和函数名或者函数序号(后面会说)获取真正的函数地址,得到地址,套上和该函数格式一模一样的函数指针。即可成功调用。
三.导出函数名问题
我们可以通过visual C++提供的工具DEPENDS.EXE来观看.dll文件,可以编译器为我们导出的函数名,在我们进行开发过程中,通常函数名都是见名知其意,那么别人就能够通过函数名来猜测我们函数的功能,那么我们如何隐藏函数名呢?
可以通过添加 def 文件,在源文件->添加->新建项->搜索def,即可添加def文件。
或者在文件中直接弄个空文件改成.def,然后在添加到项目的源文件中 也可以。
添加到项目的源文件后,需要在如下项目属性的这里,填入添加的def的文件名才能正常使用。
.def文件中写入一下文本:
EXPORTS Plus @12 Sub @15 NONAME Mul @13 Div @16
这里的Plus,Sub,Mul,DIV都是我写好的函数,如果要隐藏哪个函数名,可以根据这个来隐藏,其中@后的就是导出序号,其中NONAME表示只有序号,没有函数名,在观看.dll文件时,只能看到导出序号,看不到函数名。
由于之前我们有学习过C++,更没有学习过关于库的知识,所以在课程中可能有很多理解不到位的地方,还希望大家指出,我会非常虚心地学习,希望我们大家共同进步!