static library 在编译的时候是hardcopy,
缺点就是如果library更新了,那么软件需要重新编译
1 2 #include "Your Static Library" #pragma comment(lib, "xxxxx.lib" )
DLL 是动态链接的,所以当dll更新了之后,软件不需要重新编译:
原理就是exe在载入的时候读取导入表,导入dll到内存空间。exe在使用dll里面的function的时候直接call加载到内存的dll内存空间里面的function。
创建dll的时候如下:
1 2 3 4 extern "C" _declspec(dllexport) int __stdcall Plus (int x, int y) ;extern "C" _declspec(dllexport) int __stdcall Minus (int x, int y) ;extern "C" _declspec(dllexport) int __stdcall Multi (int x, int y) ;extern "C" _declspec(dllexport) int __stdcall Divide (int x, int y) ;
extern “C”:代表以C的方式编译,这样避免编译器自动修改函数名。C++编译方式会自动在函数名后再加一些东西避免重载
_declspec(dllexport): 让编译器知道这个函数是dll导出
__stdcall: 堆栈平衡时内平衡。Windows常用 __stdcall
使用dll分为两种方式:
隐式连接:
1 2 3 4 5 #pragma comment(lib, "DllTest.lib" ) extern "C" _declspec(dllimport) int __stdcall Plus (int x, int y) ;extern "C" _declspec(dllimport) int __stdcall Minus (int x, int y) ;extern "C" _declspec(dllimport) int __stdcall Multi (int x, int y) ;extern "C" _declspec(dllimport) int __stdcall Divide (int x, int y) ;
_declspec(dllimport): 这个声明了这个函数需要导入dll,让编译器自己去找。所以叫做隐式连接。
导入的lib里面存放了dll信息,所以编译器可以找到dll
显式连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <Windows.h> typedef int (__stdcall *lpPlus) (int ,int ) ;typedef int (__stdcall *lpMinus) (int ,int ) ;typedef int (__stdcall *lpMulti) (int ,int ) ;typedef int (__stdcall *lpDivide) (int ,int ) ;int main () { lpPlus myPlus; lpMinus myMinus; lpMulti myMulti; lpDivide myDivide; HMODULE hModule = LoadLibrary(TEXT("DllTest.dll" )); myDivide = (lpDivide)GetProcAddress(hModule, "_Divide@8" ); myPlus = (lpPlus)GetProcAddress(hModule, "_Plus@8" ); myMulti = (lpMulti)GetProcAddress(hModule, "_Multi@8" ); myMinus = (lpMinus)GetProcAddress(hModule, "_Minus@8" ); int v = myPlus(3 , 2 ); std ::cout << v << std ::endl ; }
如果正常导出,dll里面的名称和函数都是暴露的。
我们可以通过创建Module Def文件来设置dll导出时函数的名称和名字 (相当于头文件,但是这个头文件可以设置导出函数的名称和id让类似Depenency Walker不能读取到)
1 2 3 4 5 6 EXPORTS Plus @12 Minus @15 NONAME Multi @13 Divide @16
我们用Dependency Walker查一下生成的dll:
我们可以看到ordinal 已经被我们改变,并且Minus这个函数没有名字,无法通过GetProcAddress调用。
Conclusion: Static library 只是简单的copy代码到exe文件里面,写死了。
Dll 提供一张导出表,给exe用。那么exe需要调用这个dll的时候只需要 在导出表里写上需要使用的dll名和函数名 就可以加载并运行dll中的代码。所以就算dll更新了,每次打开exe都会重新加载dll进入内存,那么更新的dll就加载进内存了,只需要通过函数名在dll的导出表里面找地址就又可以使用dll里面的函数了。只要dll中function的名字和参数不变,那么exe依然可以使用dll的更新过的函数。
动态连接,就是当所有程序(exe, dll…)都加载完毕后,再连接函数,通过IAT连接
动态链接过程如下: