DLL延迟加载和即时卸载

今天我们来讲讲DLL的高级应用:DLL的延迟加载
若要延迟加载,必须要多加两个链接程序开关
/Lib:DelayImp.lib
/DelayLoad:MyDll.dll
第一个开关告诉链接程序将一个特殊的函数delayLoadHelper嵌入你的可执行模块
第二个开关有以下几个功能:
1.从可执行文件的输入节中删除MyDll.dll,这样,程序在初始化时就不会显示加载dll
2.建立一个延迟输入节,以指明哪些函数从MyDll.dll中被输入
3.通过转移到对delayLoadHelper的调用,转换到对延迟加载函数的调用

delayLoadHelper引用延迟输入节,并且知道先调用LoadLibrary之后,再调用GetProcAddress,一旦获得了延迟加载函数的地址,下次再调用延迟加载函数就无需再通过delayLoadHelper转换到对延迟加载函数的调用

但是,如果你下次调用的是dll中的另一个函数,那就还需要通过delayLoadHelper去找到这个函数的地址

延迟加载的函数也可以即时卸载__FUnloadDelayLoadedDLL2(pszDll)
但是一定要设定链接开关/Delay:unload

附上一个例子,dll是自己编写的,里面有add和sub两个函数
生成的dll的名称为DLLGenerator.dll

在这里需要注意的是,延迟加载和可卸载的开关一定要在编程软件中设置,通过#pragma comment命令设置无效

2>main.obj : warning LNK4229: 遇到无效的指令“/DelayLoad:DLLGenerator.dll”;已忽略
2>main.obj : warning LNK4229: 遇到无效的指令“/Delay:unload”;已忽略

设置如下
这里写图片描述
这里写图片描述

#include <Windows.h>
#include <stdio.h>
#include <delayimp.h>
#include "DLLGenerator.h"
TCHAR g_szModuleName[] = TEXT("DLLGenerator");
void IsModuleLoaded(PCTSTR pszModuleName);
#pragma comment(lib,"Delayimp.lib")
#pragma comment(lib,"DLLGenerator.lib")
//#pragma comment(linker,"/DelayLoad:DLLGenerator.dll") //注释的这两句
//#pragma comment(linker,"/Delay:unload")
int main()
{
    IsModuleLoaded(g_szModuleName);
    add(1, 2);
    IsModuleLoaded(g_szModuleName);
    add(1, 2);
    PCSTR pszDll = "DLLGenerator.dll";
    __FUnloadDelayLoadedDLL2(pszDll);//卸载dll
    IsModuleLoaded(g_szModuleName);
    add(1, 2);
    IsModuleLoaded(g_szModuleName);
    system("pause");
    return 0;
}

void IsModuleLoaded(PCTSTR pszModuleName)
{
    HMODULE hMod = GetModuleHandle(pszModuleName);
    char sz[100];
    #ifdef UNICODE
    wsprintfA(sz, "Module \"%S\" is %S loaded\n", pszModuleName, (hMod == NULL) ? L"not" : L"");
    #else
    wsprintfA(sz, "Module \"%s\" is %s loaded\n", pszModuleName, (hMod == NULL) ? "not" : "");
    #endif
    printf(sz);
}

运行结果
这里写图片描述
没调用add之前,dll没被加载
调用add之后,dll被加载了
又调用了一次add,但是调用了__FUnloadDelayLoadedDLL2函数,所以,dll显示没被加载
再次调用add,dll再次被加载了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章