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再次被加載了

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