20.4 延迟加载DLL--《Windows核心编程》

延迟加载的 DLL 是个隐含链接的 DLL,它实际上要等到你的代码试图引用 DLL 中包含的一个符号时才进行加载。

DLL延迟加载技术的原理,就是从导入表中去掉某dll这一项,等到正式调用DLL的时候,才会加载DLL文件。

应用场景:

  • 应用初始化加载的DLL过多,导致程序初始化时间过长。使用延迟加载,在程序不同阶段分时加载DLL可以解决这个问题。
  • 新版本系统的函数,在老版本系统中不存在时,使用延迟加载,在加载dll之前判断系统版本,不存在则不运行新函数。
  • 减小编写LoadLibrary, GetProcAddress 而像静态库函数一样直接使用。

请注意,一个导出了字段(如全局变量)的DLL是无法延迟载入的!!!否则链接失败。

 



给 DLL 设置延迟加载

请注意,/DelayLoad:MyDll.dll这个开关不能用#pragma comment(linker, "/DelayLoad:MyDll.dll")来设置。

给要使用DLL的程序设置:

 



如果需要自动卸载Dll

给要使用DLL的程序设置:
则需在可选 属性->配置属性->链接器->高级->卸载延迟加载的DLL->是 (/DELAY:UNLOAD);。此时只能调用__FUnloadDelayLoadedDll2(PCSTR szDll)函数,而不能调用FreeLibrary,并且传入的参数不包含路径,且名称与延迟加载的Dll中配置的参数必须保持一致,如果不打算卸载,就可以不指定/DELAY:UNLOAD。

 


// 卸载需要的头文件
#include <delayimp.h>
#pragma comment(lib, "delayimp")

BOOL TestReturn = __FUnloadDelayLoadedDLL2("Dll1.dll");

 


测试程序

// exe 程序
#include <iostream>
#include <tchar.h>
#include <Windows.h>
#include <StrSafe.h>
#include "MyDll.h"	// dll对应的那个头文件

// 卸载需要的头文件
#include <delayimp.h>
#pragma comment(lib, "delayimp")

// 在项目属性中添加dll对应.lib路径,附加依赖项里添加dll对应的.lib文件名
// 或者 #pragma comment (lib,"D:/Project Files/MyDll/Debug/MyDll.lib")

//延迟加载DLL的名字
TCHAR g_szDelayLoadModuleName[] = TEXT("Dll1");

//延迟加载DLL的异常捕获
LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep);

//检查是否加载
void IsModuleLoaded(PCTSTR pszModuleName)
{
	HMODULE hmod = GetModuleHandle(pszModuleName);
	char sz[100] = { 0 };
	StringCchPrintfA(sz, _countof(sz), "MyDll.dll is %S loaded.", (hmod == NULL) ? L"not" : L"");
	MessageBoxA(NULL, sz, 0, 0);
}

//延迟加载及异常捕获演示:
int main()
{
	__try
	{
		IsModuleLoaded(g_szDelayLoadModuleName);	// 还未加载
		int sum = Add(2, 43);						// 加载MyDll,调用MyDll.dll中导出的API
		printf("sum = %d", sum);					// 已加载DLL
		IsModuleLoaded(g_szDelayLoadModuleName);

		BOOL TestReturn = __FUnloadDelayLoadedDLL2("Dll1.dll");
		IsModuleLoaded(g_szDelayLoadModuleName);	// 已经卸载
	}
	__except (DelayLoadDllExceptionFilter(GetExceptionInformation()))
	{
	}
	// we can do otherthing ...
}

LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep)
{
	return -1;
}
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "MyDll.h"
#include <iostream>

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


int Add(int a, int b)
{
	return a + b;
}

// MyDll.h
#pragma once

#ifdef MYDLL_EXPORTS
#define MYDLL_API   __declspec(dllexport)
#else
#define MYDLL_API   __declspec(dllimport)
#endif


MYDLL_API int Add(int a, int b);

 

posted @ 2022-11-23 11:38  人类观察者  阅读(408)  评论(0编辑  收藏  举报