DLL总结
1:Dll内存
比如system32下有Dll.dll一份 A调用Dll.dll的时候 物理内存中会有且只有一份该dll的内存映射
然后将dll的内存通过“虚拟地址到物理地址的一种映射机制”将他们映射到A的4G虚拟内存中的一部分内存中
当再有B调用该Dll.dll的时候 仍然会将dll的内存映射到B的虚拟内存地址中 不过这个时候需要注意的是 AB 共享代码区 而数据区是不共享的 B调用Dll的时候dll之前的数据区会产生一份拷贝然后来映射到B的虚拟内存 这样A对数据区的数据产生修改时 不会影响B中的结果
最后尤其需要注意的是Dll还可以创建共享区 共享数据区不像数据区那样随着exe的调用会产生拷贝 共享数据区不产生拷贝 所有调用dll的exe都将映射该数据 当A对其中的数据修改之后 同样会影响B中的结果
语法:
共享数据区
#pragma data_seg("Share_Name");
//-->Code
#pragma data_seg();
#pragma comment(linker,"/SECTON:Share_Name,RWS")
共享数据区初始化必须赋值
在调用Dll时出现ESP错误 很可能是堆栈不平衡造成 造成的原因很可能是
声明 调用 或定义的时候出现调用约定不一致造成
问:是否只有导出函数才可以调用?
解答:不是 即使未导出的函数依然可以通过
比如DLL.dll中有导出函数void Show() 以及未导出函数void NoShow()
Dll.dll
加载到exe虚拟内存后dll的模块句柄hModule是0x100000 而Show的相对偏移是0x1005
我们来定义一个函数指针类型void (*FUNTYPE)()
这样我们通过TYPEFUN pFun = (TYPEFUN)GetProcAddress(hModule,"Show");
得到的pFun值就是0x101005 而我们可以通过pFun()来调用该函数
这样是在动态调用dll的时候常规的方法
其实即使未导出的函数NoShow()在dll中也有个相对偏移我们假设其为0x2000
那么我们在LoadLibray dll之后可以直接通过TYPEFUN pFun = (TYPEFUN )0x102000 然后pFun()来使用该函数
必须指出这是非常规使用方法 一般都不会这样使用
关于
HMODULE GetModuleHandle(LPCTSTR lpModuleName // module name);
1
:
The returned handle is not global or inheritable. It cannot be duplicated or used by another process.
2:在EXE中当lpModuleName == Null的时候 返回值就是当前的exe模块句柄
而在dll中该返回值是调用该dll的模块的句柄
调用顺序
动态加载dll时
EXE全局构造 à进入ExeMain àDll全局构造 à进入DLLMain
EXE全局析构 ß退出ExeMain ßDll 全局析构 ß退出DllMain
静态加载Dll时
DLL全局构造 à进入 DllMain àEXE全局构造 à进入ExeMain
DLL全局析构 ß退出 DllMain àEXE全局析构 ß退出ExeMain