转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家拍砖
一、延迟加载DLL:
使用目的:如果在WIN2000中设计的程序使用了WIN98没有的新函数,而要在98上运行,如果不应有延迟加载技术,将会终止进程。
方法(两步):
1、 常规建立DLL和可执行模块;
2、 链接可执行模块时,添加延迟加载开关:
a) /Lib: DelayImp.lib // 需要DelayImp.lib库(
b) /DelayLoad: MyDll.dll
///
// 实践:把下面的代码添加给需要此功能的模块
u #include <delayimp.h> // 需要的头文件
u #pragma comment(lib, "Delayimp.lib") // 库
u #pragma comment(linker, "/DelayLoad:DelayLoadLib.dll") // 延迟加载的库
u #pragma comment(linker, "/Delay:unload") // 可以手工卸载,可选
u //#pragma comment(linker, "/Delay:nobind") // 不绑定,通常不要!
///
其他方面:
3、 卸载DLL时(如果不自己卸载,则不要这项修改!):
a) 开关:/delay:unload //如果不用此开关,下面的函数将不执行操作!
b) 卸载DLL(不能使用FreeLibrary,否则函数地址不会被清除),使用:
BOOL __FUnloadDelayLoadedDLL(PCSTR szDll);//不包含路径
4、 延迟加载使.exe文件变大。阻止变大,使用开关:/Delay:nobind(不建议用)。
5. 挂钩函数。接收__delayLoadHelper的进度通知和错误通知,用法(两步):
a) 自己编写挂钩函数(如DliHook);
b) DelayImp.lib库中俩个PfnDliHook类型的变量:__pfnDliNotifyHook, __pfnDliFailureHook。将两个中的一个设置为挂钩函数的地址(PfnDliHook __pfnDliNotifyHook = DliHook)
6、 细节:
u 程序运行时,对DLL中函数的调用,实际上是对DelayImp.lib库中的__delayLoadHelper函数的调用。__delayLoadHelper引用DLL的Delay Import节(调用LoadLibrary,GetProcAddres)调用函数。
u 如果有多个DLL需要延迟加载,则要为每一个DLL设定开关。
7、 异常处理:
u 如果加载失败,产生一个软件异常(ERROR_MOD_NOT_FOUND, ERROR_PROC_NOT_FOUND),(如果不用SHE处理,进程终止!),其信息包含在DelayLoadInfo结构中,szDll为DLL名字,dlp为函数(DelayLoadProc结构),dwLastError—什么原因引发的错误;如果是成功加载,hmodCur是DLL加载到的内存地址,pfnCur为函数地址。
二、函数转发(在DLL输出节中):
#pragma comment(linker, “/export:SomeFunc=DllWork.SomeOtherFunc”)
你在DLL输出的SomeFunc实际上位于DllWork.dll中的SomeOtherFunc。
三、DLL转移(Windows98不支持):
用于强制加载程序总是首先查找应用程序的目录。仅需在应用程序的目录中添加一个空文件,文件名必须是SuperApp.local。如:可执行文件名为myPrg.exe,添加一个(转移文件)myPrg.exe.local。
四、改变模块的位置(如果你的程序带有多个DLL模块)
每个可执行模块和DLL模块都有一个首选基地址(分别是:0x00400000,0x10000000),用于标识模块映射到进程的理想地址空间。如果不能加载到首选基地址,将产生移位节。
a) 可以创建不包含移位节的模块。
u 链接开关:/FIXED。可使模块变小,但不能被改变位置,如果不能加载到首选基地址,那么他就根本不能加载,“进程异常终止”!适用于仅包含资源的DLL。
u 链接开关:/SUBSYSTEM:WINDOWS,5.0或/SUBSYSTEM:CONSOLE,5.0。
b) 如果有多个模块加载到单个地址空间,必须为每个模块设置不同的首选基地址。“工程设置”->“Link”->“Output”->Base Address=设置的首选基地址(分配粒度64K)。
c) 如果你的程序带有多个DLL模块,有必要改变首选基地址。建议使用实用程序:Rebase.exe(,详见MSDN)。(可以在链接前后执行)。
示例:rebase –b 0x61000000 myDll.dll。
u 可以在改变前后,查看基地址:dumpbin /headers myDll.dll。在“OPTIONAL HEADER VALUES”的“image base”项。
五、绑定模块:(实用程序Bind.exe,查看MSDN)。
使程序更快的初始化。在应用程序安装时执行。
示例:bind –u myPrg.exe;
u 可以在绑定前后分别查看其输入节:dumpbin /imports myPrg.exe。如果在结尾(Summary)前有“Bound to KERNEL32.dll [……] ……”,标识绑定成功!([ ] 内的内容为“时间戳”,其后面接“可读时间戳”)。
u 要把你的DLL模块(系统模块不必要)拷贝到与.exe同一个文件夹!