2014-02-06 39 views
1

我正在用Delphi構建一個插件系統(你們中的一些人一直在幫我完成這個任務)。德爾福:奇怪的行爲加載DLL與LoadLibrary

要搜索DLL文件,我使用了一個TSearchRec,它在DLL文件的exe路徑中進行搜索,然後我使用LoadLibrary來訪問它們。 然後,如果某個函數被暴露(使用GetProcAddress),我將它作爲插件加載。如果沒有,則執行FreeLibrary,然後繼續下一個文件。

在測試時,我注意到當TSearchRec發現了「borlndmm.dll」,碰巧在那個路徑中,它加載並搜索我的插件函數,當然找不到,但是當執行if FreeLibrary,我得到一個訪問衝突。

其他沒有插件的DLL位於相同的路徑,如libmariadb.dll,安全地釋放沒有錯誤。

當然這很容易解決,通過讓我的插件dll在它自己的路徑中,沒有任何其他的dll文件,即使出於性能的原因,它會更好,因爲它不需要加載任何不是它不應該至。

但我想明白爲什麼會發生。 任何想法?

謝謝 努諾·皮卡

+4

請勿將隨機DLLS加載到您的過程中。真是個壞主意。 –

+0

如果您創建了一個測試應用程序,它除了在'borlndmm.dll'上調用'LoadLibrary',然後調用'FreeLibrary',還會發生什麼?如果是這樣,請張貼使用的代碼。如果沒有,這是一個問題孤立您的應用程序本身。 (我同意@DavidHeffernan,順便說一句,將隨機DLL加載到你的過程中是一個可怕的主意。) –

+0

謝謝大衛和肯。 我會遵循這個建議! – nunopicado

回答

4

該DLL實現共享內存管理器。它被設計爲僅與加載時間鏈接一起使用。它由加載程序加載,並且在程序結束之前不會卸載。一旦它被加載,它就承擔所有將來的堆分配和釋放過程的責任。所以它改變了主機進程的行爲。它不能被動態加載。

故事的寓意不是將隨機DLL加載到您的過程中。只加載你或你的程序的用戶專門要求加載的DLL。

+0

再次感謝大衛。 這解釋了它。 因此,在這種情況下,我不能預先知道應該加載哪個dll,我只是讓它在用戶責任。 – nunopicado

5

原因爲什麼你碰到一些DLL時出現問題是因爲調用LoadLibrary在它加載DLL執行代碼 - 具體而言,DLL的初始化代碼。在Delphi項目中,這包括單元初始化部分。在borlandmm.dll的情況下,dll初始化代碼將自身插入到主機exe進程的運行時庫中,用DLL中的內存管理器替換默認的內存管理器。這不是一個可逆動作 - 它不能在DLL關閉代碼中自行移除(部分原因是DLL關閉代碼不能保證在所有情況下執行)。

所以,請小心使用LoadLibrary,因爲在您甚至知道DLL是什麼之前,您基本上正在執行任意代碼。如果您確實需要查看大量未知來源的任意DLL,則更安全的方法是將DLL作爲資源映像加載,而不是作爲可執行映像加載。這將文件加載到內存中,但不執行DLL初始化代碼。請參閱LoadLibraryEx()和LOAD_LIBRARY_AS_IMAGE_RESOURCE標誌。

正如您在之前的評論中所提到的,您可以執行許多操作來減少需要加載到用戶/管理員希望應用程序加載的DLL的數量,而不是加載所有的DLL你可以找到。

  1. 要求DLL文件名具有自定義擴展名或文件名模式。 (插件* .mod例如)
  2. 只從一個特殊的子目錄加載DLL。這適用於目錄級別的訪問控制,因爲在大多數系統上,bin目錄不能被普通用戶寫入。有人必須擁有管理員權限才能將DLL放入特殊的子目錄中。
  3. 只加載在用戶定義的配置文件中命名的DLL文件。
  4. 以上任意組合
+1

謝謝dthorpe。 我已經確保只有我的系統的真正的插件被傳遞給LoadLibrary,使用名稱,子目錄和版本信息「簽名」技術。 – nunopicado