动态库
win32环境dll原理
dll
这种PE文件由全局数据、服务函数和资源组成。windows加载dll
模块时将进程函数调用并与dll
文件的导出函数相匹配。
win32环境中,每个进程都复制了自己的读/写全局变量,若想与其它进程共享内存,必须使用内存映射文件或声明一个共享数据段。dll
需要的堆栈都是从运行进程的堆栈中分配的。
动态库导出函数这样声明:__declspec(dllexport) int myFunc();
也可以在模块定义DEF
文件中列出导出函数,相当于extern “C” __declspec(dllexport)
。
应用程序这样声明输入函数:__declspec(dllimport) int myFunc();
创建dll
.lib
文件有两种:
- 静态库中的lib:包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中
- 动态库中的lib:包含了函数所在的
.dll
文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的.dll
提供
Windows中有三个重要的dll,他们分别是Kernal32.dll,User32.dll,GDI32.dll。
/*
创建dll文件
创建项目时选择dll
创建dll的项目只有一个c文件
编译后生成.dll和.lib
*/
/*
makedll.c
*/
#include <stdio.h>
__declspec(dllexport)
void print()
{
printf("hello\n");
}
调用dll
将生成的dll
和lib
文件拷贝到测试项目目录下,测试项目-右键-属性-链接器-输入,加入lib
文件。
/*
测试项目有头文件和main.c
*/
/*
dlltest.h
*/
#ifndef _DLLTEST_H
#define _DLLTEST_H
#include<stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
void print();
#ifdef __cplusplus
}
#endif
#endif
/*
main.c
*/
#include<stdio.h>
#include "dlltest.h"
int main()
{
print();
return 0;
}
也可以直接在代码中增加使用语句如#pragma comment(lib,"MyLib.lib")
如果用LoadLibrary()
显式链接,则可以指定dll
完整路径,将dll
文件导入到进程地址空间再使用GetProcAddress()
得到dll中的函数地址再使用。手动调用动态库需要用到函数指针,是c语言的一大难点。
如果不指定路径,或者隐式链接,dll
搜索顺序如下:
- exe目录
- 当前工作目录
- windows系统目录
- windows目录
- PATH
内存泄漏
检查工具:
mtrace,memwatch。
以memwatch为例
把memwatch.h
和memwatch.c
添加进项目。主文件#include memwatch.h
.
项目右键-属性-c/c+±预处理器,添加预处理器定义MW_STDIO
和MEMWATCH
。也可以手动添加#define MEMWATCH
,#define MW_STDIO
。
memwatch会把分配的空间用0xFE
填充。例外是calloc()
,它把分配的内存用0初始化。
空间释放后memwatch把它们填充为0xFD
。