學習筆記 呼叫dll檔案的方式及注意事項

2022-04-15 09:42:33 字數 3905 閱讀 2574

最初呼叫dll檔案時,我曾犯過幾個錯誤。下面記錄幾種呼叫dll檔案的方法以及容易出錯的地方。

先來看看dll**,僅含乙個cpp檔案,工程使用了多位元組字符集:

#define dll_test _declspec(dllexport)#include 

#include

dll_test

void sayhello(std::string

str)

根據匯出函式原型,可定義如下函式指標型別

typedef void (*showmsg)(string);//

後文預設已經定義showmsg型別

一、靜態呼叫

靜態呼叫在編譯時需要lib檔案,並作函式宣告。

首先在呼叫前新增一行**:#pragma comment(lib,"dlltest.lib")

其次宣告匯入的函式:__declspec(dllimport) void sayhello(string);// :__declspec(dllimport)可改為extern,但使用__declspec(dllimport)宣告會更加高效

(2)關於函式匯入,之間新增乙個輸出函式的標頭檔案會比較方便。

**:view code

#include #include 

#include

using

namespace

std;

#pragma comment(lib,"dlltest.lib")__declspec(dllimport)

void sayhello(string

);//

typedef void (*showmsg)(string);

intmain()

二、動態呼叫

動態呼叫使用loadlibrary來載入dll檔案。函式詳細用法可看msdn。

**:view code

1 #include 2 #include 

3 #include 4

using

namespace

std;5//

#pragma comment(lib,"dlltest.lib")6//

__declspec(dllimport) void sayhello(string);

7 typedef void (*showmsg)(string);8

intmain()

9 17

if((show = (showmsg)getprocaddress(hwnd,makeintresource(1))) ==null)

18

23 show("

sunboyl

");//

利用函式指標呼叫dll中的匯出函式

24 freelibrary(hwnd);//

釋放動態鏈結庫

2526

return0;

27 }

需要特別留心的是getprocaddress函式的使用:

(1)getprocaddress函式返回farproc型別的值,需要進行強制型別轉換為對應函式指標的型別。

(2)getprocaddress函式原型:

farproc winapi getprocaddress(

__in hmodule hmodule,

__in lpcstr lpprocname

);

lpprocname是接收的是乙個函式名、變數名、或者是乙個序號。在說明此引數前先使用dumpbin.exe(可在vc或vs的bin目錄下找到)檢視一下dll檔案的輸出函式等資訊,在命令列中輸入dumpbin.exe -exports [dll檔案目錄] 即顯示下列資訊:

file type: dll

section contains the following exports for dlltest.dll

00000000 characteristics

51516c33 time date stamp tue mar 26 17:36:51 2013

0.00 version

1 ordinal base

1 number of functions

1 number of names

ordinal hint rva name

1 0 0001103c ?sayhello@@yaxv?$basic_string@du?$char_traits@d@std@@v

?$allocator@d@2@@std@@@z

summary

1000 .data

1000 .idata

3000 .rdata

1000 .reloc

1000 .rsrc

8000 .text

10000 .textbss

①前面動態呼叫dll檔案的**中我使用的序號(ordinal)來指定dlltest中sayhello輸出函式的位置,從資訊中可以看出sayhello函式的序號為1。因為lpprocname是lpcstr型別的,因此可以使用makeintresource巨集來轉換(推薦)或者將序號直接強制型別轉換為lpctstr型別。

②若想使用函式名來獲取輸出函式位置,請特別注意以下寫法是錯誤的

show = (showmsg)getprocaddress(hwnd,"sayhello");// 行a
由dumpbin.exe輸出的資訊可知,正確的函式名應該為"?sayhello@@yaxv?$basic_string@du?$char_traits@d@std@@v

?$allocator@d@2@@std@@@z",因此正確的**應該為:

show = (showmsg)getprocaddress(hwnd,"?sayhello@@yaxv?$basic_string@du?$char_traits@d@std@@v?$allocator@d@2@@std@@@z");// 行b
顯然很麻煩,這是由於c++支援函式過載,因此對不同的函式名,編譯器會採用不同的規則進行函式名轉換(貌似有個專用名叫函式名粉碎)。若希望行a中的**正確,則需修改dll**中的dll_test巨集:

#define dll_test _declspec(dllexport)  ==>>#define dll_test extern "c" _declspec(dllexport)

ordinal hint rva      name

1 0 00011348 sayhello = @ilt+835(_sayhello)

一種較好的方法就是定義乙個字尾名為def的模組定義檔案,用此來規定函式名的命名方式,這樣一來函式名的問題就解決了。而且,用模組定義檔案定義後,dll檔案將可以在delphi(__stdcall函式呼叫約定)等其他語言中使用了。對於def的詳細使用方法可以到網上查閱一下。 

曾經寫過乙個用於實現api隱藏功能的dll檔案,即批量、自動化地將c++**中的重要的api函式全部轉換為使用loadlibrary函式獲取函式位址間接呼叫,以求可執行檔案在被用od反彙編出來後,難以發現api函式(如messagebox)呼叫的位置。對於此功能的實現,我曾經用過靜態呼叫和動態呼叫兩種方式,如果是靜態呼叫,只需要在預編譯頭中插入#pragma鏈結lib檔案,然後將api函式替換為已經寫好的函式即可。但如果是使用動態呼叫的方式,因為每一次使用的時候,動態呼叫**都比較長,因此可以考慮將動態呼叫函式的**封裝成類。跑題了,哈哈。

DLL的呼叫方式

靜態呼叫靜態呼叫方式的特點是由編譯系統完成對dll的載入和應用程式結束時 dll 的解除安裝。當呼叫某dll的應用程式結束時,若系統中還有其它程式使用該dll,則windows對dll的應用記錄減1,直到所有使用該dll的程式都結束時才釋放它。靜態呼叫方式簡單實用,但不如動態呼叫方式靈活。dll e...

C 呼叫DLL學習筆記 動態呼叫

編譯dll時會生成兩個檔案,乙個是lib,乙個是dll.注意,此處生成的lib檔案和靜態庫的lib檔案不是乙個東西。呼叫dll有兩種方式 隱式載入 顯式載入。一 隱式載入方式 隱式載入方式下,需要3個檔案,分別是dll檔案 lib檔案以及對應的標頭檔案。例paneldata.dll paneldat...

檢視呼叫DLL的程式及Kill DLL檔案

以server.dll為例。如果想刪除這個dll檔案,可是系統告訴你使用中,首先要知道什麼程式在使用這個dll檔案。開始 執行 cmd 輸入命令 tasklist m c 1.txt 命令執行完成後,在c盤下找到1.txt這個檔案,ctrl f查詢dll名字,這裡是server 這樣就能看到是哪個程...