2015-09-28 24 views
6

任何人都知道是否可以優雅地測試和處理Delphi應用程序中缺少的.dll文件? 例如,我的代碼具有此功能的聲明:可以在Delphi應用程序中正常處理缺失的dll文件嗎?

function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; external 'KL2DLL32.DLL' name '[email protected]'; 

...當然,這需要的DLL文件KL2DLL32.DLL在系統上被發現,否則我的應用程序無法啓動。 我想知道是否有一些不同的方式來編碼這個,所以我的應用程序可以測試該dll文件的存在,然後相應地處理。很顯然,即使dll文件不存在,我的應用程序仍然會正常啓動。 謝謝。

+1

使用LoadLibrary並獲取過程地址。 –

回答

4

當函數聲明像這樣,你的程序就沒有什麼能夠做到缺少DLL。操作系統試圖在你的程序代碼的任何位開始執行之前解析導入的DLL函數,所以沒有你可以編寫的代碼來處理任何事情。

從Delphi 2010開始,雖然可以更改函數的聲明以使用新的延遲加載功能。在delayed指令添加到聲明的末尾:

function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; 
    external 'KL2DLL32.DLL' name '[email protected]' delayed; 

如果你使用的是老版本的Delphi,那麼你唯一的選擇是加載DLL,並在運行時函數,然後處理這些錯誤。

使用延遲的另一個好處是有SetDliNotifyHook2SetDliFailureHook2函數允許您分配掛鉤,因此您可以分別處理運行時加載通知和故障。
因此,如果在運行時找不到給定的DLL或甚至給定的函數,則可以記錄一個錯誤,甚至用另一個DLL句柄或函數指針替換它以滿足加載。

這兩個選項在another question centering on using a DLL only when required中有更詳細的討論。

+5

'delayed'功能僅僅是'LoadLibrary()'和'GetProcAddress()'函數的編譯器/ RTL包裝器。使用'delayed'的另一個好處是可以使用'SetDliNotifyHook2()'和'SetDliFailureHook2()'函數來分配鉤子,以便分別處理運行時加載通知和失敗。因此,如果在運行時未找到給定的DLL或甚至給定的函數,則可以記錄一個錯誤,甚至將其替換爲另一個DLL句柄或函數指針以滿足加載。 –

11

您輸入的結果使用所謂的加載時間或隱式鏈接進行鏈接。這是可執行文件包含元數據,它告訴OS加載器加載DLL,然後綁定到您命名的函數。如果此加載時鏈接過程失敗,則無法加載可執行文件。

您有幾個選項可以避免加載時鏈接,從而使您的程序能夠靈活地鏈接故障。

延遲載入DLL

添加delayed指令的功能導入。該文件說:

要推遲包含功能 實際需要的功能瞬間庫的加載,延遲 指令追加到導入功能:

function ExternalMethod(const SomeString: PChar): Integer; stdcall; 
    external 'cstyle.dll' delayed; 

延遲保證包含導入的函數 的庫在應用程序啓動時不加載,而是在第一次調用函數 時加載。

的文檔中包含其他有用的主題,進入更多的細節,包括如何處理錯誤:

明確樣並結合到DLL

delayed指令只是讓編譯器安排顯式加載DLL的簡明方法。您可以使用LoadLibraryGetProcAddress手動執行此操作。

  1. 呼叫LoadLibrary加載DLL。提供一個完整的路徑給DLL,或者只是它的名字。在後一種情況下,您依靠DLL搜索順序來查找DLL。撥打LoadLibrary會產生一個模塊句柄。
  2. 調用GetProcAddress來獲取指定函數指針的地址。您必須提供步驟1中的模塊句柄。
  3. 調用從步驟2返回的函數指針。
  4. 當您不再需要調用該函數時,請使用FreeLibrary來卸載該D​​LL。

在這個方法的每一步中,您都必須檢查函數返回值以防錯誤。如何處理錯誤記錄在MSDN文檔中的每個Win32 API函數中(如上所鏈接)。例如,如果無法找到DLL,則LoadLibrary返回0。您必須檢測並相應處理後果。

討論

雖然delayed指令是很方便的,我個人從來沒有使用過。根據我的經驗,無論何時我需要明確鏈接,我總會發現我需要一些額外的靈活性,這是delayed不提供的。也許我的需求很特別,但是如果你發現自己傾向於撥打LoadLibraryGetProcAddress,就不會感到驚訝。

舉個例子,就在今天,我發現自己使用LoadLibraryEx因爲我想通過LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR標誌。當您使用delayed時,這種細粒度控制不可用。

+0

還應該提到的是,「延遲」指令是在「後來的」Delphi版本之一中引入的。它不可用於德爾福2007年(我不知道它是什麼時候推出的)。 – dummzeuch

+0

@dummzeuch據Rob介紹,這是2010年。我真的不認爲2010年會成爲「後來的Delphi版本之一」! –

+0

這就是爲什麼我把「稍後」放在引號中。 – dummzeuch

相關問題