DLL 延时加载

来源:互联网 发布:阿里云服务器申请退款 编辑:程序博客网 时间:2024/06/16 09:41

1. exe加载多个dll时,初始化可能会比较慢

2. exe加载老版本dll时,如果没有相应的导出函数,exe可以做相应处理后继续执行。

 

局限性

1)导出全局变量不能延迟。

2)kernel32.dll 不能延迟, LoadLibrary and GetProcAddress

3) 不能在dllmain中调用延迟加载的函数。

 

onedll.dll project

//onedll.h

#ifdef ONEDLL_EXPORTS
#define ONEDLL_API __declspec(dllexport)
#else
#define ONEDLL_API __declspec(dllimport)
#endif

extern "C" ONEDLL_API int fnLib(void);

extern "C" ONEDLL_API int fnLib2(void);

 

//onedll.cpp

#include "onedll.h"

ONEDLL_API int fnLib(void)
{
 return 42111;
}
ONEDLL_API int fnLib2(void)
{
 return 42222;
}

oneexe.exe project

//oneexe.cpp


#include <Windowsx.h>
#include <tchar.h>
#include <StrSafe.h>
#include <Windows.h>
#include <iostream>

#include <Delayimp.h>   // For error handling & advanced features
#include "..\onedll.h"

#pragma comment(lib, "onedll.lib")
#pragma comment(lib, "Delayimp.lib")

// Note: it is not possible to use #pragma comment(linker, "")
//       for /DELAYLOAD and /DELAY

// The name of the Delay-Load module (only used by this sample app)
wchar_t g_szDelayLoadModuleName[] = L"onedll";

// Forward function prototype
LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep);


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


void IsModuleLoaded(PCTSTR pszModuleName) {

   HMODULE hmod = GetModuleHandle(pszModuleName);
   wchar_t sz[100];
   StringCchPrintfW(sz, _countof(sz), L"Module \"%s\" is %sloaded.",
      pszModuleName, (hmod == NULL) ? L"not " : L"");
   std::wcout << sz << std::endl;
}

//int WINAPI _tmain(HINSTANCE hInstExe, HINSTANCE, PTSTR pszCmdLine, int)
int _tmain(int argc, _TCHAR* argv[])
{

   // Wrap all calls to delay-load DLL functions inside SEH
   __try {
      int x = 0;

      // If you're in the debugger, try the new Debug.Modules menu item to
      // see that the DLL is not loaded prior to executing the line below
      IsModuleLoaded(g_szDelayLoadModuleName);

      x = fnLib();  // Attempt to call delay-load function

      // Use Debug.Modules to see that the DLL is now loaded
      IsModuleLoaded(g_szDelayLoadModuleName);

      x = fnLib2(); // Attempt to call delay-load function

      // Unload the delay-loaded DLL
      // NOTE: Name must exactly match /DelayLoad:(DllName)
  PCSTR pszDll = "onedll.dll";
      BOOL bRet = __FUnloadDelayLoadedDLL2(pszDll);      // link -> advanced -> Unload delay loaded DLL:yes

      // Use Debug.Modules to see that the DLL is now unloaded
      IsModuleLoaded(g_szDelayLoadModuleName);

      x = fnLib();  // Attempt to call delay-load function

      // Use Debug.Modules to see that the DLL is loaded again
      IsModuleLoaded(g_szDelayLoadModuleName);
   }
   __except (DelayLoadDllExceptionFilter(GetExceptionInformation())) {
      // Nothing to do in here, thread continues to run normally
   }

   // More code can go here...

   return(0);
}


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


LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep) {

   // Assume we recognize this exception
   LONG lDisposition = EXCEPTION_EXECUTE_HANDLER; 

   // If this is a Delay-load problem, ExceptionInformation[0] points
   // to a DelayLoadInfo structure that has detailed error info
   PDelayLoadInfo pdli =
      PDelayLoadInfo(pep->ExceptionRecord->ExceptionInformation[0]);

   // Create a buffer where we construct error messages
   char sz[500] = { 0 };

   switch (pep->ExceptionRecord->ExceptionCode) {
   case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND):
      // The DLL module was not found at runtime
      StringCchPrintfA(sz, _countof(sz), "Dll not found: %s", pdli->szDll);
      break;

   case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND):
      // The DLL module was found, but it doesn't contain the function
      if (pdli->dlp.fImportByName) {
         StringCchPrintfA(sz, _countof(sz), "Function %s was not found in %s",
            pdli->dlp.szProcName, pdli->szDll);
      } else {
         StringCchPrintfA(sz, _countof(sz), "Function ordinal %d was not found in %s",
            pdli->dlp.dwOrdinal, pdli->szDll);
      }
      break;

   default:
      // We don't recognize this exception
      lDisposition = EXCEPTION_CONTINUE_SEARCH; 
      break;
   }

   if (lDisposition == EXCEPTION_EXECUTE_HANDLER) {
      // We recognized this error and constructed a message, show it
      //chMB(sz);
    std::wcout << sz << std::endl;
   }

   return(lDisposition);
}

// 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);
}

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

//note:

生成exe后,可以rename onedll.dll 名字,或者 delete 某个导出函数 测试, dependency walker 查看延迟加载的dll图标

1.一个dll中申请、释放内存

2.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager 可修改加载程序的搜索顺序

3. 隐式加载,可执行程序包含导出dll工程的头文件,其__declspec(dllimport) 比我们不include头文件而直接用extern 效果高

HMODULE WINAPI GetModuleHandle(__in_opt  LPCTSTR lpModuleName);
传NULL,返回可执行文件的句柄,传DLL,返回dll实例句柄
DWORD WINAPI GetModuleFileName(__in_opt  HMODULE hModule, __out     LPTSTR lpFilename, __in      DWORD nSize);
传NULL,返回可执行文件的名字,传DLL,返回dll名字

DllMain的序列货调用,系统保证一个线程执行完DllMain才会让另一个线程执行

_DllMainCRTStartup -> __DllMainCRTStartup --> _CRT_INIT, DllMain
_DllMainCRTStartup -> __DllMainCRTStartup --> DllMain, _CRT_INIT


如果用户不添加DllMain函数,将调用C/C++运行库提供的下面函数
BOOL WINAPI DllMain(
        HANDLE  hDllHandle,
        DWORD   dwReason,
        LPVOID  lpreserved
        )
{
#if defined (CRTDLL)
        if ( dwReason == DLL_PROCESS_ATTACH && ! _pRawDllMain )
                DisableThreadLibraryCalls(hDllHandle);
#endif  /* defined (CRTDLL) */
        return TRUE ;
}

 

 

 

 

0 0
原创粉丝点击