2008-12-14 103 views
18

我不理解使用DLL的.def文件的要點。.def文件C/C++ DLL

它看起來代替了在您的DLL代碼中使用顯式導出的需要(即顯式__declspec(dllexport)),但是我不能在不使用這些文件時生成一個lib文件,這會在以後創建鏈接器問題DLL。

那麼,如何在與客戶端應用程序鏈接時使用.defs,它們是否替換使用頭文件或.lib文件的需要?

回答

17

我的理解是,.def文件提供了__declspec(dllexport)語法的替代方法,並且可以顯式指定導出函數的序號。如果僅通過序號(ordinal)導出某些函數,該函數不會顯示有關函數本身的很多信息(例如:許多操作系統內部DLL的導出函數僅由序數),這會非常有用。

查看reference page

請注意.def文件中的名稱必須與二進制文件中的名稱相匹配。因此,如果您使用C或C++與'extern「C」{...}「,名稱不會被破壞;否則,您必須使用正確的mangled名稱來生成DLL的特定版本的編譯器。 __declspec()函數全部自動執行此操作。

+0

正如M.克魯尼說的:「別的什麼?」。 +1。作爲一名Windows開發人員,我的經驗是DEF文件是「舊的方式」,應該被棄用(如果尚未)。 – paercebal 2008-12-14 15:20:22

+0

是的.def文件早於__declspec語言擴展。在.def文件中,您無法使用__declspec或#pragmas做任何事情。這包括花哨的鏈接器技巧,如重命名或轉發API。 – 2008-12-14 20:22:06

3

我還沒有用過很多DLL,但我的理解是,對於導出的C++函數,你需要使用「__declspec(dllexport)」,而對於導出的C函數,你應該寫入.def文件。這可能是因爲C++函數支持重載,但C函數不支持。

+1

是的。重載能力=在.def文件中煩人指定的裝飾名稱。 C和C++在這裏沒有根本的區別,但是人機工程學和文化差異很大。 – 2012-07-04 12:21:00

3

.DEF文件在16位窗口中更爲常見,它們通常是指定應導出哪些符號的唯一方法。

此外,他們提供了一種通過序號值(@ 1,@ 2等)而不是按名稱指定導出的方法。當性能非常重要時,例如在視頻驅動程序中,使用這種查找符號的方法。

3

我的理解是,.def文件實際上並不指定哪個apis需要導出。它只包含導出的apis和它們的序號。如果你想實際導出一個特定的api,你需要在聲明的api和__declspec(dllimport)的定義中指定__declspec(dllexport)。

def文件的優點是,它可以幫助您保持與已經存在的dll的後臺字符兼容性。即它維護apis的序數。假設你在dll中添加了一個新的api,那麼鏈接器會查看你的.def文件生成ne wapi的序號,以便舊apis的序號完好無損。

因此,如果客戶端代碼使用最新的dll,它不會破壞現有的apis。

7

對於那些有興趣的人仍然...能夠鏈接到dll和def文件,你還需要一個lib文件。在Windows中,這可以使用'LIB'工具從def進行。請參閱下面的命令行方式的示例。

lib /machine:i386 /def:sqlite3.def 

希望這可以幫助別人。

+0

+1。那正是我要找的 – fmuecke 2012-04-17 12:49:55

22

我發現將__declspec(dllexport)和.def文件一起用於創建可移植DLL,即可以從使用不同編譯器編譯或使用不同編譯器設置編譯的代碼中調用的DLL。

只要在你的函數聲明中加入__declspec(dllexport),就可以使你的DLL「至少在Windows」上「導出」這些函數,以便可以從DLL之外調用它們。

但是,向build中添加一個列出所有導出函數的.def文件後,您可以停止Microsoft編譯器(例如)將導出的下劃線和尾隨參數寬度信息添加到導出的函數名稱中(至少在何時結合__stdcall指令,對便攜性也很有用)。例如。函數聲明

void foo(int i); 

可能最終會被導出爲「_foo @ 4」,如果你不小心調用約定和DEF文件使用。

將GetProcAddress()調用作爲加載並在運行時顯式連接到DLL的一部分時,在符號表中保留導出的函數名稱時沒有這種名稱修飾會非常方便。即獲得一個指向上述函數foo()在運行時(假設它是出口的話),你最好只是想呼籲:

HANDLE dllHandle = LoadLibrary("mydll.dll"); 
void* fooFcnPtr = GetProcAddress(dllHandle, "foo"); 

有了一些相應的錯誤的情況下,當然檢查!

在構建DLL時,在函數聲明中使用.def文件加上__stdcall,__declspec(dllexport)和extern「C」將確保上述客戶端代碼適用於各種編譯器和編譯器設置。