VC中隱式鏈結無 LIB動態鏈結庫的方法

2021-06-22 01:24:43 字數 3825 閱讀 6319

dumpbin /exports foo.dll > foo.def 

modify foo.def by def format 

lib /def: foot.def to create foo.lib 

vc中隱式鏈結無.lib動態鏈結庫的方法

茅煦鵬  [email protected]

摘要:  本文提出在不具備動態鏈結庫的原始檔或. lib輸入庫檔案或欲呼叫windows未公開函式的情況下重建.lib檔案的方法,並給出相應的例子。

undocumented function,no source ,implicitly link

由於我們經常要呼叫一些第三方廠商或其他編譯器編寫的動態鏈結庫,但是一般都不提供原始檔或.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將函式編譯後會在函式名前面加上"@"字首,在函式名後加上"@"和引數的位元組數。

用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的提供者那兒得到乙個包含輸出函式的標頭檔案(.h檔案)、乙個用於鏈結的輸入庫(.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拷入dllcaller\debug目錄。

//宣告函式原型

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* argv)

編譯器產生如下錯誤:

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* argv)

隱式鏈結無 LIB動態鏈結庫

由於我們經常要呼叫一些第三方廠商或其他編譯器編寫的動態鏈結庫,但是一般都不提供原始檔或.lib檔案,而作為vc隱式鏈結到dll implicitly link to the dll 呼叫,這些卻是必需的。本文將主要討論在沒有原始檔及.lib輸入庫檔案或欲呼叫windows未公開函式的情況下重建.li...

2021 01 06 隱式鏈結

dll編譯完成後生成 dll與 lib,但其生成的 lib檔案與靜態鏈結庫的不同,動態鏈結庫中的 lib裡不包含 只包含一些輔助性的資訊。如果有了 dll與 lib檔案即可使用隱式鏈結。declspec dllimport stdcall int plus int x,int y declspec ...

隱式鏈結隱式鏈結 第1部分 了解隱式跟蹤

該帖子的編輯日期為 2019年7月22日 以便在重疊網格專案的示例中更好地描述專案放置。當觀察人們逐漸熟悉css grid時,我注意到一些問題比其他人更容易吸引人們,或者在構建布局時面臨更多挑戰。本簡短的系列文章將深入 這些常見問題,旨在更好地理解grid,以便您可以預期布局問題,並在出現問題時更輕...