DLL动态加载与静态加载
静态库与动态库
- 要了解静态库与动态库的区别,先了解什么是库。库说白了就是一段编译好的二进制代码,加上头文件供别人调用。一般用于下面两种场景:
- 需要将某些功能代码供别人使用,但又不希望别人看到源码,就可以以库的形式进行封装,只暴露出头文件供调用
- 对于一些不会进行大的改动的代码,可以打包成库,减少编译时间
- 静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做静态,是因为静态库在目标程序编译链接的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。
而动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。与静态库相反,动态库在目标程序编译链接时并不会将需要的二进制代码都“拷贝”到可执行文件中,而是仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程
dll动态加载与静态加载
静态加载又称静态调用也称隐式调用,大部分工作由操作系统完成,使用的时候只要包含对应头文件与对应的库文件
动态加载又称动态调用也称显示调用,通过windows``API函数加载和卸载dll,主要函数如下:LoadLibrary加载dll
- GetProcAddress获取要调用的函数的地址
- FreeLibrary释放dll
- 什么是动态链接库?
动态链接库是dll文件,广泛的存在于程序的安装目录下 - 动态链接库有什么用?
通常的说,动态链接库文件里面包含了程序运行所需要的代码和数据。
也就是说动态链接库文件也是可执行文件,但是它不能单独运行,动态链接库是给其他可执行文件提供函数的。
比如一个程序,可能是由一个.exe文件和10个.dll文件组成,当双击.exe文件运行程序的时候,系统也会把其他的10个.dll文件加载到内存 - 使用动态链接库有什么好处?
增强了模块性,一个使用dll的人,不需要关注功能怎么实现的,只需要包含头文件,然后将dll放到exe所在的目录下,就可以使用其中的函数了
更新软件更为方便,将程序分成多个部分,更新的时候,也许只需要更新其中几个dll即可,或者更新exe也可以,只要接口没有改变就行。
windows通过这种机制去节约内存 比如CreateWindow这个函数,大多数窗口程序都需要调用,但是如果每个程序的内存空间都有一份此代码,就大大浪费了内存 - 动态链接库的缺点是什么
假如某一个dll丢失或者损坏了,程序就不能运行
假如使用了静态对象库,那么可以制作一个不依赖其他文件的exe,发布的时候只需要发布exe即可
使用动态链接库操作步骤
- dll文件是给别人提供函数的,不会作为一个程序单独去运行,也就是没有什么第一行执行代码的概念
- 通常都不需要去管DllMain,不会在里面写代码
- DllMain会在程序运行、程序退出、线程被创建、线程被卸载时被调用
- dll中的函数并不是都能够提供给其它可执行文件使用,只有导出的函数才可以
导出的方式有两种:- 声明导出
在函数的声明前加上: extern “C” _declspec(dllexport) - def文件导出
- 声明导出
添加一个名为”xxx.def”的文件,并写入以下内容 LIBRARY DLL名 DESCRIPTION “my DLL” EXPORTS 函数名 @ 序号 ; @1 表示导出函数的序号
- 调用dll中函数的方式,有两种:
- 隐式调用
包含头文件,头文件中含有导出函数的声明
载入lib文件 #pragma comment(lib,””);
直接调用函数即可 - 显式调用
(前提:使用显示调用不需要头文件,但是需要知道函数的原型,比如返回值类型,各个参数的类型)
LoadLibrary() 将目标dll强行加载到本进程中
GetProcAddress()获得函数的地址
- 隐式调用
include typedef void(*FUN)(); FUN g_Fun; int main(){ HMODULE hModule = LoadLibrary(L”Dll1.dll”); g_Fun = (FUN)GetProcAddress(hModule, “fun1”); g_Fun(); system(“pause”); }
- lib文件的差别
随着dll一起生成的lib文件,称为导入库,里面是没有代码和数据的,是链接信息,供编译器在exe文件与dll文件之间做链接
还有一种是静态对象库,编译的时候会将静态库中使用到的代码数据编译到exe中,exe发布就不需要携带很多文件