Window动态库相关知识
1.先从一个dll工程创建开始
//add.h
#ifdef DLLEXPORT
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif
extern "C"
{
DLLAPI int add(int ra, int rb);
};
//add.cpp
#include "add.h"
int add(int ra, int rb)
{
return ra+rb;
}
第一行的宏定义是为了使dll创建和使用模块共用一个头文件,便于项目的维护。__declspec(dllexport)关键字的作用是导出dll中的函数,变量等等,__declspec(dllimport)的作用,就我目前所知道,是为了让执行模块更好的区别是否为dll导出函数等,具体是否有其他方面的作用,还在学习中。
至于为什么使用extern “C”,是为了考虑到c和c++模块之间的兼容问题,我们应该知道C++编译器之所以支持重载,关键技术就是对函数进行改名,使之标识函数名和参数类型两个方面的信息,使用上面的关键字,就是明确的告知编译器,我想要以c的方式编译这些的文件,编译器接到这个信息后便不会为之改名了。如果执行模块是c编写的,函数不改名,而dll模块是c++编写的,则要改名,没有使用这个关键字进行声明,执行模块在调用dll的时候便会报错。需要注意的是这个关键字只能用在c++编写的dll中。
2.关于在dll中申请内存空间的问题。
如果在dll中有这么一个函数,用来申请内存,
void* AllocMemory()
{
void* p = malloc(1000);
return p;
}
在exe执行模块中进行如下调用
int main
{
void* p = AllocMemory();
free(p);
return 0;
}
上面的做法有可能出现错误的(具体什么原因,不是特别清楚,各位同学有知道的,可以跟我说下),防止可能出现的问题,最有效的方法就是做到谁申请,谁释放的原则,也就是说,在dll提供内存申请接口的同时,也要提供一个释放接口,释放的方式要一直(malloc,relloc,calloc使用free释放,而new,用delete)。具体方法如下:
Dll模块中添加释放内存接口:
void* AllocMemory()
{
void* p = malloc(1000);
return p;
}
void FreeMemory(void *p)
{
free(p);
}
执行模块进行如下调用
int main
{
void* p = AllocMemory();
FreeMemory(p);
return 0;
}
知识补充:
Dll载入到进程就是虚拟内存映射的过程,此时所有的内存申请,对象创建都是在执行模块的地址空间中完成的,所以在dll中申请的空间,务必在dll完成释放,否则在执行进程结束前,这部分空间一直保持着占用状态。