如何在沒有 .obj 和源碼的情況下制作32位的輸入庫文件 *.lib
(藥師)hwman@163.net
名次解釋:
輸入庫:import library
輸出函數(shù):export function
使用Microsoft Library Manager,lib.exe的32位版本。
本文解釋如何在沒有 .obj 和源碼的情況下建立所給出的.dll對應(yīng)的輸入庫。不幸的是,沒有一個(gè)32位的實(shí)用工具能夠直接從.dll文件中建立對應(yīng)的輸入庫。(16位版本的有,比如Borland 的 implib, 但制作出來的.lib文件不能為32位版本的編譯器所用)。
注意:該方法不一定適用于非微軟的開發(fā)工具所產(chǎn)生的dll。
通常,當(dāng)我們使用VC建立一個(gè)有輸出函數(shù)的.dll時(shí),連接過程會同時(shí)產(chǎn)生對應(yīng)的輸入庫。但是對于第三方提供的.dll,他們不一定提供所對應(yīng)的輸入庫。這時(shí)候,如果我們使用“裝載時(shí)動態(tài)連接load-time dynamic linking”,就需要首先產(chǎn)生對應(yīng)的輸入庫。(如果你使用“運(yùn)行時(shí)動態(tài)連接run-time dynamic linking”,你就不需要這個(gè)輸入庫了)
有兩種方法可以產(chǎn)生所給的.dll的輸入庫。
一、建立.def文件,用 lib /def: 命令
如果這個(gè).dll文件的輸出函數(shù)是通過C調(diào)用接口聲明的,很幸運(yùn),你可以很容易地建立一個(gè).def文件來建立對應(yīng)的輸入庫。要使用C調(diào)用約定,一般是在函數(shù)聲明時(shí)在前面附加_cdecl 屬性。如果我們在CL命令行中沒有附加 /Gz 或/Gr選項(xiàng),_cdecl 就是缺省的屬性。
給出了一個(gè)C接口輸出函數(shù)的.dll,你可以按照以下幾個(gè)步驟建立輸入庫:
用 dumpbin /exports <.dll文件名> 獲得.dll的輸出符號表。以"ordinal hint name"為標(biāo)題的 "name" 那一列就是它的符號表。
建立一個(gè).def文件,文件包含一個(gè)EXPORTS 段。把上面用dumpbin列出的符號放在EXPORTS段中。對于_cdecl 函數(shù),這些符號就是調(diào)用程序中的符號。
用lib /def:<.def 文件名>來產(chǎn)生輸入庫文件。輸入庫文件的基本名就是.def文件的基本名。用 /OUT 可以指定庫的名字。
例:一直mydll.dll 文件的輸出函數(shù)都尊選C調(diào)用借口,它的輸出函數(shù)有:mydll1 mydll2
則相應(yīng)的.def文件為
library mydll
exports
mydll1
mydll2
二、存根函數(shù)法
對于不是用C調(diào)用約定的輸出函數(shù),情況比較復(fù)雜。然而,如果你使用C++和其他更復(fù)雜的命名修飾時(shí),這卻是很普遍的。要使用這種方法,你至少要有描述該.dll文件的接口的頭文件。
由頭文件函數(shù)原型建立存根函數(shù):
如果原型中有"__declspec(dllimport)",把它改為"__declspec(dllexport)"
對于沒有返回值的C源碼中C函數(shù)以及C++源碼中的C函數(shù)(用了 extern "C" 修飾符),把函數(shù)原型中的分號替換為空的花括號("{}")。
對于帶有返回值得C++函數(shù)(全局或者成員函數(shù)),你必須替該函數(shù)建立一個(gè)傀儡函數(shù)體,并返回一個(gè)相應(yīng)類型的傀儡函數(shù)值(因?yàn)楹瘮?shù)中沒有返回值是非法的)。對每一個(gè)成員函數(shù)同樣處理。記住,我們只是要讓lib工具能夠產(chǎn)生正確的輸入庫,所以這些函數(shù)體是無關(guān)要緊的。對于C++類,你也可以在類定義的地方通過函數(shù)原型完成函數(shù)實(shí)現(xiàn),只要你在編譯時(shí)禁用內(nèi)聯(lián)函數(shù)就行了。
通常,頭文件中僅僅列出函數(shù)參數(shù)的類型。例如,Geta(int)。加入傀儡函數(shù)時(shí)必須指定一個(gè)傀儡參數(shù),比如Geta(int x)。要不,會產(chǎn)生一個(gè)C2055錯(cuò)誤。
示例:
假設(shè)mydll.dll的頭文件如下:
// mydll.H
extern "C" __declspec(dllimport) void _stdcall Function(void);
class __declspec(dllimport) CMyClass {
int a;
long b;
public:
int Geta(int);
long Getb();
CMyClass();
};
你用來產(chǎn)生輸入庫的源文件應(yīng)該如下:
// mydll.CPP
extern "C" __declspec(dllexport) void _stdcall Function(void) {}
class __declspec(dllexport) CMyClass {
int a;
long b;
public:
int Geta(int x) {return 111;}
long Getb() {return 111;}
CMyClass() {}
};
一旦寫出了該存根函數(shù),你所要做的就是把他編譯為.obj文件:
CL /c /ob0 mydll.cpp
要記得禁用內(nèi)聯(lián)函數(shù)。如果使用了內(nèi)聯(lián)函數(shù),編譯器會認(rèn)為這里沒有函數(shù)調(diào)用,因此它會略過函數(shù)體。
一旦你有了.obj文件,你就可以使用 lib /def: 來建立輸入庫了:
lib /def: mydll.obj
關(guān)于dll命令的更多信息,可以參考msdn中有關(guān)LIB Reference 的部分。