延迟加载的 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);

20.4 延迟加载DLL--《Windows核心编程》的更多相关文章

  1. windows核心编程 DLL技术 【转】

    注:本文章转载于网络,源地址为:http://blog.csdn.net/ithzhang/article/details/7051558 本篇文章将介绍DLL显式链接的过程和模块基地址重定位及模块绑 ...

  2. 《Windows核心编程系列》二十谈谈DLL高级技术

    本篇文章将介绍DLL显式链接的过程和模块基地址重定位及模块绑定的技术. 第一种将DLL映射到进程地址空间的方式是直接在源代码中引用DLL中所包含的函数或是变量,DLL在程序运行后由加载程序隐式的载入, ...

  3. 《windows核心编程系列》十七谈谈dll

    DLL全称dynamic linking library.即动态链接库.广泛应用与windows及其他系统中.因此对dll的深刻了解,对计算机软件开发专业人员来说非常重要. windows中所有API ...

  4. 《windows核心编程系列》十九谈谈使用远程线程来注入DLL。

    windows内的各个进程有各自的地址空间.它们相互独立互不干扰保证了系统的安全性.但是windows也为调试器或是其他工具设计了一些函数,这些函数可以让一个进程对另一个进程进行操作.虽然他们是为调试 ...

  5. C++Windows核心编程读书笔记

    转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔 ...

  6. 【转】《windows核心编程》读书笔记

    这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入 ...

  7. 【windows核心编程】 第六章 线程基础

    Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ①    一个是线程的内核 ...

  8. 《Windows核心编程》读书笔记 上

    [C++]<Windows核心编程>读书笔记 这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对 ...

  9. 【Windows】windows核心编程整理(下)

    windows核心编程整理(上) windows核心编程整理(下) 线程的堆栈 每当创建一个线程时,系统就会为线程的堆栈(每个线程有他自己的堆栈)保留一个堆栈空间区域,并将一些物理存储器提交给这个以保 ...

  10. 《Windows核心编程系列》十四谈谈默认堆和自定义堆

    堆 前面我们说过堆非常适合分配大量的小型数据.使用堆可以让程序员专心解决手头的问题,而不必理会分配粒度和页面边界之类的事情.因此堆是管理链表和数的最佳方式.但是堆进行内存分配和释放时的速度比其他方式都 ...

随机推荐

  1. Java求一个集合的所有子集

    转载请注明出处: 求一个集合的所有子集表示从一个集合当中,任取任意项或不取,所能得到的所有结果,比如有一个集合{a,b,c,d},那么{a,b}, {b, d}等都是它的子集,空集也是它的子集, 一个 ...

  2. 玛珍,玛珍,margin!

    最近在整理巩固面试相关的资料,又看到了熟悉的老朋友:margin,当时觉得其读起来很亲切,现在又发现很多遗忘的知识点. 了解margin margin,译为"外边缘",在CSS作为 ...

  3. Latex常用数学符号输入方法

    引用CSDN博文 https://blog.csdn.net/qq_25368751/article/details/87888974

  4. 【rt-thread】构建自己的项目工程 -- 初始篇

    现以stm32f429igt6芯片的板子 & Keil5编译环境为例,记述构建适配自己板子的rt-thread工程的过程 1.拿到rt-thread源码,进入bsp/stm32/librari ...

  5. [springmvc] - 配置文件 springmvc-config.xml 和 web.xml

    springmvc-config.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmln ...

  6. JS - console多个值

     Promise.all([p1, p2]).then(         (res) => {           let [p1, p2] = res;           console.l ...

  7. grpc-环境与示例

    1. 数据传输基本原理 2. grpc环境安装 代码生成器 go get -u github.com/golang/protobuf/protoc-gen-go // 会自动在 $GOPATH/bin ...

  8. Grub2 内核启动参数总结

    Grub2 内核启动参数总结 部分参数 biosdevname=0 net.ifnames=0 # 注意这个配置会修改网卡的名字, 比如之前是ens192 # 添加如上两个内容后就会变成 eth0 类 ...

  9. Harbor的逻辑备份与学习

    Harbor的逻辑备份与学习 背景 一直想处理一下一个有网络冲突的Harbor镜像服务器 但是因为网络层自己水平一直是不是非常自信 加上Harbor容器使用的compose的玩法, 自己不敢直接处理. ...

  10. [转帖] Linux命令拾遗-使用blktrace分析io情况

    https://www.cnblogs.com/codelogs/p/16060775.html 原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介# 一般来说,想检 ...