一、什么是库
库从本质上来说是一种代码重用的方式,即预先编译可执行代码的二进制格式,
可以被载入内存中,执行,比如C运行库,里面实现了基本的函数,我们无需在写一遍,直接调用接口即可.
库分为静态库和动态库两种,
二、静态库和动态库区别
1.静态函数库
这类库名字一般是xxx.lib,利用静态编译的文件比较大,因为这个函数库的所有数据
都会被整合进目标代码中
优点: 即编译后执行程序不需要外部的函数库支持,因为所有使用的函数都被编译进去了,
缺点: 如果静态函数库里的东西改变了,那你的程序也必须重新编译.
2.动态函数库
库名字一般是 xxx.dll(也可以包含xx.lib用于编译时的链接处理,也可以不包含,
直接动态调用 )
动态函数库不会被编译到目标代码中,你的程序执行到相关代码时才调用库函数.
优点: 因此动态函数库产生的执行文件比较小,因为没有整合到你的程序
动态函数库改变不会影响你的程序。动态函数库升级方便.
缺点: 程序在运行环境中必须提供相应的库,
三、静态库实例
1. 选择Win32项目
2.预编译头,自动生成stdafx.h头文件,作用是获得更快的编译速度
3.添加一个类
4.添加加法接口,和c++一样,不做讲解. 注意函数的实现要放在cpp文件,
虽然没错误, 但是违背了静态库的初衷,
5.实现单独的接口,不依赖类,比如实现一个减法接口
这样声明 extern "c"让编译器这部分但按c形式进行编译
在头文件
extern "C"
{
int sub(int a,int b);
int Doubles(int a);
}
6.然后编译生成
7.导入使用,接口声明在.h文件,所以需要.h找到函数,
使用代码导入lib
#pragmacomment(lib,"lib名.lib")
如果你要方便,可以直接放工程目录
如果你的lib文件在别的地方,你可以说设置附加库目录
如果你不想在代码导入lib 可以在这里导入
8.创建对象调用接口
CTestLib t; //调用类接口 int a = t.Add(10,10); //调用函数 int subs = sub(30,10); int dbInter = Doubles(30);
四、动态库实例
1.创建Win32项目,DLL即可
2.DllMain函数
作用: 动态库dll和静态库区别是: 动态库是可以独立运行的文件,
通俗说他和可执行文件没有多大区别
当其他可执行程序(exe或者其他dll)调用该dll时候,系统会执行一个入口函数.
做一些初始化之类的工作,当然这个入口函数和可执行文件exe有一个最大的区别
就是这个入口函数 不是必须的, 也就是说没有这个函数依然能编译dll
参数二表明了系统调用DLL的原因:
DLL_PROCESS_ATTACH 进程加载
DLL_PROCESS_DETACH 进程卸载
DLL_THREAD_ATTACH 线程加载
DLL_THREAD_DETACH 线程卸载
通过这四种情况分析系统何时调用轮到DllMain
3.DLL_PROCESS_ATTACH
一个程序要调用DLL里的函数,首先要把DLL文件映射到进程的地址空间,
要把一个DLL文件映射到进程的地址空间,两种方法:
静态链接和动态链接的LoadLibrary或者LoadLibarayEx
当一个DLL文件被映射到进程的地址控件时,系统调用该DLL的DllMain函数,
传递fdwReason参数为DLL_PROCESS_ATTACH,这种调用只发生在第一次映射
如果同一个进程来为已经映射进来的DLL再次调用,系统只会增加DLL使用次数,
4.DLL_PROCESS_DETACH
DLL被从进程地址空间解除,DLL处理该值时,应处理相关清理工作
什么时候DLL被从进程的地址空间解除映射呢?有两种情况
1_) FreeLibrary解除DLL映射(有几个LoadLibrary,就要有几个FreeLibrary)
2_) 进程结束而解除DLL映射,在进程结束前还没有解除DLL时,进程结束会解除
DLL映射,如果是调用 TerminateProcess终止指定进程和其线程
系统就不会调用DLL_PROCESS_DETACH
5.DLL_THREAD_ATTACH
当进程创建线程时,系统查看当前映射到进程地址空间中的所有DLL文件映射,
DLL_THREAD_ATTACH会触发
新创建的线程负责执行DLL的DllMain函数, 当所有的DLL都处理完后,系统才运行
进程执行其他的线程函数
每次新建线程都会调用, 线程中建立线程也会调用。
6.DLL_THREAD_DETACH
线程调用ExitThread结束线程,(线程函数返回时, 系统也会自动调用ExitThread)
系统查看当前进程空间中所有的DLL映射文件, 并DLL_THREAD_DETACH调用DllMain函数
通知所有DLL执行线程清理工作
五、动态库导入导出
1.打开C++ 预处理器
区分动态库是导入的还是导出的
2.有一个自定义的预定义,这个预定义随便是什么,因为这个
只在你这个工程有效,其他的无效
3.如果有这个定义说明是导出
如果没有这个定义说明是导入
现在这个宏定义是定义的,所以他是导出.
4.类名前面添加即可
5.添加类函数
声明 不需要调用形式, 给类添加即可
实现
C语言形式 全局接口 声明前加上调用形式
6.编译生成
7.导入和使用动态库,所以操作和静态库一样,就是多个个DLL文件
这个文件和exe放一个目录,会静态链接
8.动态库还有一种链接方式,动态加载dll: LoadLibrary
所谓动态载入,就是程序运行时候不必一开始就载入dll。
在程序需要的时候,动态加入进来,
这样我们就不再使用lib来做静态连接, 甚至连,h头文件 都不用了,
直接用GetProcAddress来使用,但是这样的方式来说,都最好只用extern "C"
开头的接口,
9.下载Depends反编译工具 查看dll的内容
上面3个是类风格的
全局形式的Sub函数
10.通过动态链接使用动态函数链接库
动态调用的函数,你得知道函数原型,才能行.
HMODULE hdl = ::LoadLibrary(L"TestDll.dll"); if(!hdl) printf("load error"); //获得接口的函数指针. 第二个参数是函数名 FUNC_SUB fnuc = (FUNC_SUB)::GetProcAddress(hdl,"Sub"); if(fnuc != NULL) { printf("110减去20=%d",fnuc(110,20)); } //解除映射 ::FreeLibrary(hdl);
原文地址:http://blog.51cto.com/12158490/2107000