【windows核心編程】DLL相關(2)

來源:互聯網
上載者:User

標籤:c   style   class   blog   code   java   

 

關於DLL的消極式載入

 

消極式載入DLL,使用的是隱式載入方式,當為exe使用的DLL指定為消極式載入的時候,連接器會將exe的【匯入段】中去除該DLL的相關資訊,同時在exe中嵌入一個新的【消極式載入段】表示要從該DLL中匯入哪些函數。

通過讓對消極式載入函數的調用跳轉到delayimp.lib中的__delayLoadHelper2函數,來完成對消極式載入的DLL的解析。

當exe中第一次調用了一個消極式載入的DLL中的某個匯出函數時,載入器才會將該DLL載入到進程地址空間中。需要注意的是:雖然此時已經載入了DLL,但是未調用到的其他函數,還是需要在調用的時候才能被修複(修複即不再通過__delayLoadHelper2函數來解析)。

消極式載入的DLL也可以卸載,當再次調用該DLL中的函數時,再次載入DLL到進程地址空間。

 

消極式載入 及支援卸載DLL的步驟,以ADll.dll為例

①項目屬性--配置屬性--連結器--輸入--消極式載入的DLL

 輸入DLL的名字,注意這裡:卸載的時候使用的DLL的名字不能包含路徑 並且 大小寫必須和這裡設定的一樣。

/DELAYLAOD:[DLLName]

 

 

②項目屬性--配置屬性--連結器--進階--消極式載入的DLL

  選擇【支援卸載(/DELAY:UNLOAD)】

  

 

 

 ③載入DelayImp.lib靜態庫

  __delayLoadHelper2函數和__FUnloadDelayLoadedDLL2函數都在這個靜態庫中。

 

#pragma comment(lib, "DelayImp.lib") 

#include <delayimp.h>

 

④添加DLL的標頭檔 或者 添加DLL匯出函式宣告


extern "C" __declspec(dllimport) int __stdcall Add(int a, int b);

 

 

 demo

void CUseADll2Dlg::OnBnClickedButton1(){    // TODO: 在此添加控制項通知處理常式代碼    __try    {         int sum = Add(10, 20);     }    __except(1)    {        AfxMessageBox(_T("異常"));    }}void CUseADll2Dlg::OnBnClickedButton2(){      //檢測該DLL是否載入了    HINSTANCE hInst = GetModuleHandle(TEXT("ADll.dll"));}void CUseADll2Dlg::OnBnClickedButton3(){     //參數DLL的名字不能包含路徑,並且 大小寫要和/DELAYLOAD設定的一致    BOOL bRet = __FUnloadDelayLoadedDLL2("ADll.dll");}

 

 

 函數轉寄站

函數轉寄站是DLL【輸出段】中的一個條目,用來將一個函數調用【轉寄】到另一個DLL中的另一個函數。

可用【dumpbin  -exports  XX.dll】查看

 

在DLL中設定函數轉寄站:

#pragma comment(linker, "/export:本DLL匯出函數=其他DLL.函數名")

 

e.g.

#pragma comment(linker, "/export:Add=SecondDll.Sum")

將本DLL中的匯出函數Add【轉寄】到另一個名為SecondDll的DLL中函數Sum。

 

經過實驗,發現這裡需要特別注意:#pragma來表示轉寄的函數名一定是經過name manling改變後的! 

如下:

//DLL1中的匯出函數,Add#pragma comment(linker, "/export:[email protected][email protected]")extern "C" __declspec(dllexport) int __stdcall Add(int a, int b);

 

 

//DLL2中的匯出函數Sumextern "C" __declspec(dllexport)  int __stdcall Sum(int a, int b){    return a + b;}

 

 

一開始,當我試圖這樣寫時:#pragma  comment(lib, "exports:Add=Dll2.Sum)

看起來好像沒有問題,可實際上,GetProcAddress總是失敗的,經過測試,發現必須使用經過編譯器name manling改變過後的名字,從depends查看如下

 

 

 

 

 

所以必須使用改變過後的名字才可以,這一點也同樣體現在GetProcAddress中,如下

HINSTANCE hInst = LoadLibrary(TEXT("Dll1.dll"));    if (NULL == hInst)    {        AfxMessageBox(_T("LoadLibrary 失敗"));    }    typedef  int (__stdcall *  PUNC)(int, int);  //必須加上__stdcall    PUNC pfnAdd = (PUNC)GetProcAddress(hInst, "[email protected]"); //這裡的名字也必須是改編後的    if (NULL == pfnAdd)    {        AfxMessageBox(_T("GetProcAddress失敗")); return;    }    int sum = pfnAdd(100, 400);    char chBuffer[100] = {0};    sprintf_s(chBuffer, "result is %d", sum);    AfxMessageBox(CString(chBuffer));

 

 

另外,如果想要使用未經改變的名字,那麼可以在VS編譯器下使用

extern "C"  __declspec(dllexport)   int  __cdecl  Add(int a,  int b);

使用extern  "C" 和  __cdecl呼叫慣例組合方式,在VS下的名字就是Add。

 

結論:

①DLL函數轉寄時,轉寄到的函數也必須是匯出函數,兩者的呼叫慣例以及名字改編方式最好一致

②在設定轉寄時,必須使用經過改編後的名字

③在定義匯出函數的函數指標時,要加上呼叫慣例,並且GetProcAddress()函數也要用改編後的名字

 

 

 

 

已知DLL

在註冊表HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDlls中列出的那些

 

在使用LoadLibrary或LoadLibraryEx時,參數中的DLL是否帶.dll尾碼導致的不同情況:

①帶.dll尾碼

首先去掉尾碼,比如LoadLibrary("xx.dll"),首先去掉尾碼,然後去上述註冊表路徑下尋找【名稱】為"xx"的項目,然後找到其對應的【資料】,即帶.dll尾碼的dll名字(這個名字可能和LoadLibrary時使用的不一樣),如果在註冊表中找不到該【名稱】為"xx"的項目,則再去搜尋路徑依次尋找"xx.dll", 如果在註冊表中找到了該DLL名字,則去%systemroot%\sytstem32目錄中去尋找該xx.dll,系統會並且只會該目錄下尋找該xx.dll,如果找到了則載入進進程地址空間,如果找不到則失敗返回。

 

 ②不帶.dll尾碼

按照正常搜尋路徑搜尋DLL

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.