DLL延迟加载工程分析

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家拍砖!

 

 

源码下载地址: http://www.rayfile.com/zh-cn/files/bc9d6854-eb7e-11e1-a73e-0015c55db73d/

 

一、载入dll的另一方法:

1、  导出dll

(1)       在自己的.cpp文件中定义extern"C"__declspec(dllexport)

     这样就得到了导出的接口

    (2) 提供给调用者接口.h文件,eg:

#ifndef DELAYLOADLIBAPI 

#define DELAYLOADLIBAPI extern "C" __declspec(dllimport)

#endif

 

///////////////////////////////////////////////////////////////////////////////

DELAYLOADLIBAPI int fnLib();

DELAYLOADLIBAPI intfnLib2();


 

由于是由宏DELAYLOADLIBAPI 开关,在此.h之前如果没有定义,那么就用dllimport。

2、使用导出dll的模块

(1)#incldue  上面讲到的 接口.h文件

这样会去运行目录下查找DelayLoadLib.dll,如果存在就加载它。

#include "..\20-DelayLoadLib\DelayLoadLib.h"   // My DLL function prototypes

 

(2)判断是否加载此dll

  HMODULE hmod =GetModuleHandle(pszModuleName);

返回值如果不为空,表明已经加载了。

(3)使用接口.

 

二、     延迟加载

此功能实现了当使用函数时再加载DLL,且可以用API __FUnloadDelayLoadedDLL2主动卸载DLL。

1、添加延迟加载的dll,及链接的lib(实验证明可以不加lib链接)

(1)在目标EXE工程中设置延迟加载的DLL,注意:它的路径是从执行的exe路径开始算的,如果是同一目录,那么直接写名字即可;

如果路径错误,那么会报以下警告:

这是因为VS2008编译器中的确延迟加载DLL模块的使用就是在代码中加入/DELALOAD选项,所以这与我们在代码中直接加入的效果是一样。(出现此警告,表示延迟加载没有实现)

(2)在“附加依赖项”里添加延迟加载的dll对应的lib,它的路径是从exe工程的路径开始算的。

 

如果不加此lib,编译时报以下 警告:

但不影响执行的情况。

我把链接的lib去掉后,执行时的情况是:

第一步:  case dliNotePreLoadLibrary

第二步:

DLL延迟加载工程分析_第1张图片

第三步:case dliFailLoadLib

 

第四步:进入异常处理函数

case VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND):

提示dll没有找到

一开始以前是.lib加载不到引起MSVCR90D.dll加载不到,后来发现是由MSVCR90D.dll没加载到引起的整个执行失败。解决这个问题请参考文章<<>>

 

 

2、工程设备里的属性默认是不支持卸载的,为了使卸载DLL的API函数__FUnloadDelayLoadedDLL2有效 ,我们修改工程属性:

 

3、根据我们绑定的钩子及弹出指明是否加载的Msg框,可以看到执行的过程:

绑定钩子:

// Tell __delayLoadHelper2 to call my hook function
PfnDliHook __pfnDliNotifyHook2  = DliHook;
PfnDliHook __pfnDliFailureHook2 = DliHook;

 

// Skeleton DliHook function that does nothing interesting
FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli) {

   FARPROC fp = NULL;   // Default return value

   // NOTE: The members of the DelayLoadInfo structure pointed
   // to by pdli shows the results of progress made so far. 

   switch (dliNotify) {
   case dliStartProcessing:
      // Called when __delayLoadHelper2 attempts to find a DLL/function
      // Return 0 to have normal behavior or nonzero to override
      // everything (you will still get dliNoteEndProcessing)
      break;

   case dliNotePreLoadLibrary:
      // Called just before LoadLibrary
      // Return NULL to have __delayLoadHelper2 call LoadLibary
      // or you can call LoadLibrary yourself and return the HMODULE
      fp = (FARPROC) (HMODULE) NULL;
      break;

   case dliFailLoadLib:
      // Called if LoadLibrary fails
      // Again, you can call LoadLibary yourself here and return an HMODULE
      // If you return NULL, __delayLoadHelper2 raises the 
      // ERROR_MOD_NOT_FOUND exception
      fp = (FARPROC) (HMODULE) NULL;
      break;

   case dliNotePreGetProcAddress:
      // Called just before GetProcAddress
      // Return NULL to have __delayLoadHelper2 call GetProcAddress,
      // or you can call GetProcAddress yourself and return the address
      fp = (FARPROC) NULL;
      break;

   case dliFailGetProc:
      // Called if GetProcAddress fails
      // You can call GetProcAddress yourself here and return an address
      // If you return NULL, __delayLoadHelper2 raises the 
      // ERROR_PROC_NOT_FOUND exception
      fp = (FARPROC) NULL;
      break;

   case dliNoteEndProcessing:
      // A simple notification that __delayLoadHelper2 is done
      // You can examine the members of the DelayLoadInfo structure
      // pointed to by pdli and raise an exception if you desire
      break;
   }

   return(fp);
}



 

第一步:x = fnLib(); // Attempt to call delay-load function

 Case dliNotePreLoadLibrary

第二步: case dliNotePreGetProcAddress

 

第三步:x =fnLib2();// Attempt to call delay-load function

Case  dliNotePreGetProcAddress

第四步:__FUnloadDelayLoadedDLL2(pszDll);

第五步:case  dliNotePreLoadLibrary

第六步:case dliNotePreGetProcAddress

你可能感兴趣的:(DLL延迟加载工程分析)