由於我們經常要呼叫一些第三方廠商或其他編譯器編寫的動態鏈結庫,但是一般都不提供原始檔或.lib檔案,而作為vc隱式鏈結到dll(implicitly link to the dll)呼叫,這些卻是必需的。本文將主要討論在沒有原始檔及.lib輸入庫檔案或欲呼叫windows未公開函式的情況下重建.lib檔案的方法。在建立之前,我們首先要了解一下dll輸出函式的幾種方式。
一、從dll中輸出函式的方式(calling conventions)
_cdecl是c和c++程式的預設呼叫方式。每乙個呼叫它的函式都包含清空堆疊的**,所以產生的可執行檔案大小會比呼叫_stdcall函式的大。函式採用從右到左的壓棧方式。vc將函式編譯後會在函式名前面加上下劃線字首。
_stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上"@"和引數的位元組數。
_fastcall方式的函式採用暫存器傳遞引數,vc將函式編譯後會在函式名前面加上"@"字首,在函式名後加上"@"和引數的位元組數。
動態鏈結庫標頭檔案
extern "c" void _stdcall stdcallproc(void);
extern "c" void _cdecl cdeclproc(void);
extern "c" void _fastcall fastcallproc(void);
動態鏈結庫實現檔案
#include
extern "c" void _stdcall stdcallproc(void)
extern "c" void _cdecl cdeclproc(void)
extern "c" void _fastcall fastcallproc(void)
動態鏈結庫輸出函式定義
library "noname"
exports
stdcallproc @1 noname
cdeclproc @2
fastcallproc @3
編譯後生成noname.lib,輸出函式_cdeclproc,_stdcallproc@0,@fastcallproc@0;生成的noname.dll在exescope等pe格式的工具中只能看到cdeclproc和fastcallproc函式,因為stdcallproc被指定noname屬性,沒有名字輸出,類似於windows未公開函式。
二、可執行程式呼叫dll的方式
可執行程式可以採用隱式鏈結(implicit linking)或顯式鏈結(explicit linking)兩種方式呼叫乙個dll。使用顯式鏈結時,使用dll的程式在使用之前必須載入(loadlibrary)載入dll從而得到乙個dll模組的控制代碼,然後呼叫getprocaddress函式得到輸出函式的指標,在退出之前必須解除安裝dll(freelibrary),因為不是本文重點,具體例程請參考有關文件。顯然,在呼叫大量的函式時這種方法會很不方便。
使用隱式鏈結時,可執行程式鏈結到乙個包含dll輸出函式資訊的輸入庫檔案(.lib檔案)。作業系統在載入使用可執行程式時載入dll。可執行程式直接通過函式名呼叫dll的輸出函式,呼叫方法和程式內部其他的函式是一樣的。
三、重建.lib輸入庫檔案
根據微軟的建議,要想隱式地鏈結到乙個dll,可執行程式必須從dll的提供者那兒得到乙個包含輸出函式的標頭檔案(.**件)、乙個用於鏈結的輸入庫(.lib檔案)。願望是很好的,但是一般情況下,我們都無法得到第三方動態鏈結庫的輸入庫檔案,或者我們需要呼叫windows未公開函式。如果你是使用delphi或visual basic開發程式,那麼,你只要簡單的申明一下函式和輸出庫就可以了。但是,使用vc的朋友們只好重建.lib檔案了。
1.刪掉第一步中生成的noname.lib(假設我們沒有這個檔案)。
2.用微軟的dumpbin.exe:dumpbin /exports noname.dll>noname.def,留下noname.def檔案的輸出段:
ordinal hint rva name
2 0 00001005 cdeclproc
3 1 0000100f fastcallproc
1 0000100a [noname]
修改為:
library "noname"
exports
cdeclproc @2
fastcallproc @3
nonameproc @1
//請注意與第一步中noname.def的區別:nonameproc可以自己指定為任何名字
再執行lib.exe /def:noname.def即可生成noname.lib檔案(但如果這個動態鏈結庫不僅僅包含_cdecl型別函式,那麼這個noname.lib還不是最終可用的.lib檔案,具體請看下文)。
3.建立乙個名為dllcaller的win32控制台程式,將剛才生成的noname.dll和noname.lib拷入dllcallerdebug目錄。
//宣告函式原型
extern "c" void _stdcall nonameproc(void);
extern "c" void _cdecl cdeclproc(void);
extern "c" void _fastcall fastcallproc(void);
//鏈結輸入庫檔案
#pragma comment(lib,"debug\noname.lib")
int main(int argc, char* ar**)
編譯器產生如下錯誤:
dllcaller.obj : error lnk2001: unresolved external symbol @fastcallproc@0
dllcaller.obj : error lnk2001: unresolved external symbol
_nonameproc@0
根據錯誤提示資訊將noname.def更改如下:
@fastcallproc@0 @3
nonameproc@0 @1
重新生成noname.lib,即可重新編譯dllcaller.exe。
四、呼叫windows未公開函式
根據以上分析,下面給出乙個簡單的呼叫window98系統shell32.dll中序號為60的未公開函式,執行後將出現重新啟動的對話方塊。
據此生成shell32.lib
library "shell32"
exports
shshutdowndialog@4 @60
// dllcaller.cpp:呼叫未公開函式的控制台程式
//函式宣告
extern "c" long _stdcall shshutdowndialog(long lshutdown);
//鏈結輸入庫檔案
#pragma comment(lib,"debug\shell32.lib")
int main(int argc,char* ar**)
VC中隱式鏈結無 LIB動態鏈結庫的方法
dumpbin exports foo.dll foo.def modify foo.def by def format lib def foot.def to create foo.lib vc中隱式鏈結無.lib動態鏈結庫的方法 茅煦鵬 xpmao 163.net 摘要 本文提出在不具備動態鏈結...
動態鏈結庫 dll和 lib
測試環境vs2008 一 關於動態鏈結庫 2 載入方式 隱式鏈結,編譯工程時,需要先新增.lib檔案。可以直接通過編譯環境新增,還可以通過 新增 pragma comment lib,lib 二 關於extern c cdecl stdcall 這裡是雙下劃線,雙下劃線和單下劃線是有區別的 2 我們...
動態鏈結庫dll,靜態鏈結庫lib, 導入庫lib
目前以lib字尾的庫有兩種,一種為靜態鏈結庫 static libary,以下簡稱 靜態庫 另一種為動態連線庫 dll,以下簡稱 動態庫 的導入庫 import libary,以下簡稱 導入庫 靜態庫是乙個或者多個obj檔案的打包,所以有人乾脆把從obj檔案生成lib的過程稱為archive,即合併...