DLL延迟加载

Carewhose

发布日期: 2018-12-20 12:31:21 浏览量: 1815
评分:
star star star star star star star star star star
*转载请注明来自write-bug.com

背景

我们在开发程序的时候,通常会使用第三方库,但是并不是所有的第三方库都会提供静态库文件,而是提供动态库文件。这样,我们的程序就需要相应的DLL文件才能加载启动。

现在,我们想大家介绍一种DLL延迟加载技术,使用延迟加载方式编译链接可执行文件。这样,可执行程序就可以先加载执行,所依赖的DLL在正式调用时才被加载进来。

这样做的好处就是,我们可以把必需的DLL文件以资源的形式包含到我们的程序中,并使用DLL延迟加载技术延迟加载必需的DLL。这样,在正式调用必需的DLL之前,程序都是可以正常执行的,我们可以在程序运行的时候,就把在资源中的DLL释放到本地,所以,程序所有功能就可以正常执行了。我们只需把EXE文件发送给用户,而不需要附加DLL文件了,也不需要担心程序会丢失DLL文件。

实现原理

DLL延迟加载原理

本程序以加载第三方库——skin++库为例子进行讲解演示。我们在导入库文件,编码完成后,对程序编译链接等到可执行文件。我们使用PEview.exe查看可执行文件的导入表,就可知道可执行文件所必需的DLL文件。

上面可以知道,导入表中有SkinPPWTL.dll文件,也就是说,程序加载运行的时候,SkinPPWTL.dll文件必需存在,否则程序不能正常加载启动。

DLL延迟加载技术的原理,其实就是在导入表中去掉SkinPPWTL.dll这一项,等到DLL被正式调用的时候,才会加载DLL文件。这样,程序在正式调用DLL之前,都是可以正常执行的。

DLL延迟加载实现

DLL延迟加载的实现,并不需要任何编码,只需要设置下开发环境的链接选项即可。本程序使用的是VS2013开发环境,还是继续上述skin++皮肤库的例子进行讲解。DLL延迟加载实现的步骤为:

属性—>链接器—>输入—>延迟加载的DLL—>输入:SkinPPWTL.dll

这样,DLL延迟加载就完成了。这时,我们编译链接,再用PEview.exe查看可执行程序的导入表信息:

可见,导入表中没有SkinPPWTL.dll文件了。所以,程序在正式调用该DLL之前,程序都是可以加载执行的。

接下来,我们就把SkinPPWTL.dll作为资源导入,在加载皮肤之前就释放DLL到本地上,这样程序正常加载执行了。

编码实现

皮肤加载

  1. // 加载界面皮肤
  2. void LoadSkin()
  3. {
  4. // 加载皮肤
  5. // 获取当前目录
  6. char szCurrentPath[MAX_PATH] = { 0 };
  7. GetCurrentPath(szCurrentPath, MAX_PATH);
  8. // 构造路径
  9. ::lstrcat(szCurrentPath, "\\Skins\\");
  10. ::lstrcat(szCurrentPath, "dogmax2.ssk");
  11. // 加载皮肤
  12. ::skinppLoadSkin(szCurrentPath);
  13. }

资源释放

  1. // 释放资源
  2. BOOL FreeMyResource(UINT uiResouceName, char *lpszResourceType, char *lpszSaveFileName)
  3. {
  4. HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(uiResouceName), lpszResourceType);
  5. if (NULL == hRsrc)
  6. {
  7. FreeRes_ShowError("FindResource");
  8. return FALSE;
  9. }
  10. DWORD dwSize = ::SizeofResource(NULL, hRsrc);
  11. if (0 >= dwSize)
  12. {
  13. FreeRes_ShowError("SizeofResource");
  14. return FALSE;
  15. }
  16. HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);
  17. if (NULL == hGlobal)
  18. {
  19. FreeRes_ShowError("LoadResource");
  20. return FALSE;
  21. }
  22. LPVOID lpVoid = ::LockResource(hGlobal);
  23. if (NULL == lpVoid)
  24. {
  25. FreeRes_ShowError("LockResource");
  26. return FALSE;
  27. }
  28. FILE *fp = NULL;
  29. fopen_s(&fp, lpszSaveFileName, "wb+");
  30. if (NULL == fp)
  31. {
  32. FreeRes_ShowError("LockResource");
  33. return FALSE;
  34. }
  35. fwrite(lpVoid, sizeof(char), dwSize, fp);
  36. fclose(fp);
  37. return TRUE;
  38. }

程序测试

我们直接运行EXE程序,程序正常执行,DLL成功释放,皮肤加载成功:

总结

该程序实现并不难,只是多了个设置链接选项。这样,程序就会更加简洁,而且方便易用。这算是程序开发的一个小技巧吧,希望能对大家有所帮助。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download DelayLoadDll_Test.7z ( 7.42mb, 8次下载 )

keyboard_arrow_left上一篇 : 运行单一实例 判断指定进程是否具有管理员权限 : 下一篇keyboard_arrow_right



Carewhose
2018-11-07 11:52:02
通过设置程序链接选项来实现 DLL 延迟加载,在程序初始化阶段再释放必需的 DLL 文件到本地上

发送私信

你总是喊着努力努力,可是又坚持了多久

11
文章数
14
评论数
最近文章
eject