延迟加载的 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. 人人都是 Serverless 架构师 | “盲盒抽奖”创意营销活动实践

    作者 | 寒斜 & 江昱 当 Serverless 与低代码这两个不同的技术共同相交于同一个业务时会有怎样的价值展现?本文以 "盲盒抽奖" 这个 Serverless De ...

  2. python进阶(8)--测试函数与类

    一.测试函数(unittest) 1.源文件方法(name_function.py): def get_formatted_name(first,last): """生成 ...

  3. 05_二叉树的层次遍历II

    二叉树的层序遍历 II 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 . (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 示例 1: 输入:root = [3,9,20 ...

  4. ffmpeg 字幕解码

    原文: https://blog.csdn.net/u011283226/article/details/102241233 [写在前面] 在前一篇,我已经讲过了读取外挂字幕并显示的方法:理解过滤图并 ...

  5. MySQL-多表查询练习

    首先创建练习所需要的数据表 储备:建表操作: CREATE TABLE `t_dept` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `deptName` VARC ...

  6. [转帖]max_allowed_packet 与 SQL 长度的关系

    https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000210013 适用版本:V2.1.x.V2.2.x.V3.1 ...

  7. K8S Only IPV6的创建过程之二 完整版

    K8S Only IPV6的创建过程之二 完整版 整体过程 1. 阿里云新增一台虚拟机, 开通IPV6.与数据库,redis实现物理隔离. 并且进行环境基本处理,安装kubeadm等组件. 2. ku ...

  8. [转帖]TiUP Cluster 命令合集

    https://docs.pingcap.com/zh/tidb/stable/tiup-component-cluster TiUP Cluster 是 TiUP 提供的使用 Golang 编写的集 ...

  9. OpenPower服务使用node-exporter prometheus以及grafana进行性能监控的流程

    OpenPower服务器性能监控操作流程 1. 前言 最近看了很多prometheus以及influxdb进行性能监控的帖子,简单学习了下influxdb是一个单纯的时序数据库,prometheus是 ...

  10. python+selenium+opencv验证滑块

    我们在使用selenium爬虫的时候在登录时经常会遇到滑块验证码问题,导致登录受阻,正所谓万事开头难. 登录就登录不进去更别提往后的操作的.今天以登录京东后台来演示下如何破解滑块. 一.登录 首先我们 ...