2012-08-16 65 views
0

我使用LoadlibraryGetprocaddress來鏈接一些WinApis以進行運行時鏈接。正如預期的那樣,它工作正常。運行時鏈接API和「-ldllname」編譯器選項

但是對於一些Apis,我只是用-ldllname作爲編譯選項。同樣的選項會導致一些API的鏈接器錯誤,並且需要加載dll。

這裏有沒有什麼特別的區別,就是一些特定的API需要運行時連接,其他的API可以使用-ldllname選項?如何分類這些類型的API?

更新:我觀察什麼是API,支持UNICODE和ANSI即 這是後綴爲「W」和「A」的API,得到了靜態 聯自籌解決?我對麼?糾正我,如果我錯了!

爲什麼一些API需要運行時鏈接和其他解決與靜態 鏈接自己(-l選項)?有什麼理由呢?

+0

在編譯器選項中是否指定了庫存在的目錄?你會得到什麼錯誤? – Rohan 2012-08-16 08:34:03

+0

是的,我指定了庫路徑。這隻發生在一些API和其他-l選項工作正常。 – 2vision2 2012-08-16 08:36:27

回答

1

我使用的LoadLibrary

這將是採取在DLL中的隱式相關性的例子。 LoadLibrary是一個由kernel32.dll(Windows api DLL)導出的函數。它實際上存在兩個版本,LoadLibraryA和LoadLibraryW。分別是非Unicode和Unicode版本的函數。您將得到一個或另一個,這取決於編譯時是否有UNICODE宏#defined。

所以這與將導出與GetProcAddress動態鏈接完全相反,您必須告訴鏈接器您的程序與kernel32的依賴關係爲-l選項。在運行時,DLL會在你自己的代碼開始運行之前自動加載。

對操作系統DLL有隱式依賴是非常正常的。而且不可避免的是,你永遠不能動態鏈接kernel32.dll,這將是一個雞與蛋的問題。

+0

因此,我的問題中更新的部分是正確的? – 2vision2 2012-08-16 09:49:41

+0

技術上不行,只是「非常正常」,你當然可以動態加載操作系統DLL。如果api函數僅適用於更高版本的操作系統,那麼這是非常正常的事情。 – 2012-08-16 09:56:00

+0

感謝您的答案。如果可能的話,你可以解釋爲什麼som API需要運行時鏈接,其他人可以通過靜態鏈接本身來解析(-l選項)?對不起,更多的麻煩.. – 2vision2 2012-08-16 10:19:57

1

這實質上就是你所描述的。我會跳過這裏的非Windows,但它在本質上是相似的)。

因此,有兩種不同的情況:

編譯時間(靜態)鏈接:代碼包括所有的函數,類等,但沒有機構申報。你必須(如通過-ldllname),以提供編譯時正確的庫文件:

void sayHello(void); // the declaration might be a bit more complicated, e.g. adding a calling convention or dllimport/dllexport, etc. 

運行時(動態)鏈接:代碼包括最小的函數體基本上是裝載庫和檢索地址(通過函數你命名):

HMODULE lib = LoadLibrary("hello.dll"); // loading happening somewhere once 

void sayHello(void) { 
    myfnproc call = GetProcAddress(lib, "sayHello"); 
    call(); // actual call 
} 

FreeLibrary(lib); // unloading happening somewhere else 

雖然運行時方法更復雜,但它有一個很大的優勢:您能夠處理缺失的庫。例如。如果用戶缺少一些庫,可以告訴他在哪裏下載它(或者甚至自己下載它),並且鏈接的代碼可以很容易地被替換(例如插件功能)。有了靜態鏈接,你運氣不好:如果依賴關係丟失,程序將不會運行。

+0

感謝您的回答(+1)。但我的疑惑是,爲什麼一些API需要鏈接和其他API可以通過靜態鏈接本身解決? – 2vision2 2012-08-16 08:56:23

+0

這是一個設計選擇。例如。對於OpenGL/GLEW,可能不是所有的函數都可能由本地實現提供,所以使用動態鏈接來跳過不可用的東西。 – Mario 2012-08-16 09:01:56

+0

馬里奧請看看我的問題的更新部分。我對嗎? – 2vision2 2012-08-16 09:07:49