什麼是動態連結程式庫(DLL)以及常見問題

來源:互聯網
上載者:User
動態|連結|問題

  概要

  本文說明什麼是動態連結程式庫 (DLL) 以及在使用 DLL 時可能發生的各種問題。

  然後,本文說明在開發您自己的 DLL 時應該考慮的一些進階問題。在說明什麼是 DLL 的過程中,本文將說明動態連結方法、DLL 依賴性、DLL 進入點、匯出 DLL 函數以及 DLL 故障排除工具。

  本文最後將從較高的層次對 DLL 與 Microsoft .NET Framework 程式集作一比較。

  簡介

  對於“適用於”一節中列出的 Microsoft Windows 作業系統,作業系統的大量功能是由動態連結程式庫 (DLL) 提供的。另外,當您在這些 Windows 作業系統之一上運行某一程式時,該程式的很多功能可能是由 DLL 提供的。例如,某些程式可能包含很多不同的模組,而該程式的每個模組都包含在 DLL 中並從中分發。

  使用 DLL 有助於促進代碼的模組化、代碼重用、記憶體的有效使用和減少所佔用的磁碟空間。因此,作業系統和程式能夠更快地載入和運行,並且在電腦中佔用較少的磁碟空間。

  當程式使用 DLL 時,一個稱為依賴性的問題可能導致該程式無法運行。當程式使用 DLL 時,就會建立一個依賴項。如果其他程式改寫和損壞了該依賴項,原來的那個程式就可能無法成功運行。

  在引入 Microsoft .NET Framework 之後,大多數依賴性問題都已經通過使用程式集消除了。

  什麼是 DLL?

  DLL 是一個包含可由多個程式同時使用的代碼和資料的庫。例如,在 Windows 作業系統中,Comdlg32 DLL 執行與對話方塊有關的常見函數。因此,每個程式都可以使用該 DLL 中包含的功能來實現“開啟”對話方塊。這有助於促進代碼重用和記憶體的有效使用。

  通過使用 DLL,程式可以實現模組化,由相對獨立的組件組成。例如,一個計帳程式可以按模組來銷售。可以在運行時將各個模組載入到主程式中(如果安裝了相應模組)。因為模組是彼此獨立的,所以程式的載入速度更快,而且模組只在相應的功能被請求時才載入。

  此外,可以更為容易地將更新應用於各個模組,而不會影響該程式的其他部分。例如,您可能具有一個工資計算程式,而稅率每年都會更改。當這些更改被隔離到 DLL 中以後,您無需重建或安裝整個程式就可以應用程式更新。

  下表說明了 Windows 作業系統中的一些作為 DLL 實現的檔案: •ActiveX 控制項 (.ocx) 檔案

  ActiveX 控制項的一個樣本是日曆控制項,它使您可以從日曆中選擇日期。

  •控制台 (.cpl) 檔案

  .cpl 檔案的一個樣本是位於控制台中的項。每個項都是一個專用 DLL。

  •裝置驅動程式 (.drv) 檔案

  裝置驅動程式的一個樣本是控制列印到印表機的印表機驅動程式。

  DLL 的優點

  下表說明了當程式使用 DLL 時提供的一些優點: •使用較少的資源

  當多個程式使用同一個函數庫時,DLL 可以減少在磁碟和實體記憶體中載入的代碼的重複量。這不僅可以大大影響在前台啟動並執行程式,而且可以大大影響其他在 Windows 作業系統上啟動並執行程式。

  •推廣模組式體繫結構

  DLL 有助於促進模組式程式的開發。這可以協助您開發要求提供多個語言版本的大型程式或要求具有模組式體繫結構的程式。模組式程式的一個樣本是具有多個可以在運行時動態載入的模組的計帳程式。

  •簡化部署和安裝

  當 DLL 中的函數需要更新或修複時,部署和安裝 DLL 不要求重建立立程式與該 DLL 的連結。此外,如果多個程式使用同一個 DLL,那麼多個程式都將從該更新或修複中獲益。當您使用定期更新或修複的第三方 DLL 時,此問題可能會更頻繁地出現。

  DLL 依賴項

  當某個程式或 DLL 使用其他 DLL 中的 DLL 函數時,就會建立依賴項。因此,該程式就不再是獨立的,並且如果該依賴項被損壞,該程式就可能遇到問題。例如,如果發生下列操作之一,則該程式可能無法運行: •依賴 DLL 升級到新版本。

  •修複了依賴 DLL。

  •依賴 DLL 被其早期版本覆蓋。

  •從電腦中刪除了依賴 DLL。

  這些操作通常稱為 DLL 衝突。如果沒有強制實現向後相容性,則該程式可能無法成功運行。

  下表說明了為了協助最大限度地減少依賴性問題而在 Microsoft Windows 2000 和較高版本的 Windows 作業系統中引入的更改: •Windows 檔案保護

  在 Windows 檔案保護中,作業系統禁止未經授權的代理程式更新或刪除系統 DLL。因此,當程式安裝操作嘗試刪除或更新被定義為系統 DLL 的 DLL 時,Windows 檔案保護將尋找有效數位簽章。

  •專用 DLL

  通過專用 DLL 可以使程式避免遭受對共用 DLL 進行的更改。專用 DLL 使用版本特定資訊或空 .local 檔案來強制要求程式所使用的 DLL 的版本。要使用專用 DLL,請在程式根資料夾中尋找 DLL。然後,對於新程式,請向該 DLL 中添加版本特定資訊。對於舊程式,請使用空 .local 檔案。每個方法都告訴作業系統使用位於程式根資料夾中的專用 DLL。

  DLL 故障排除工具

  可以使用多個工具來協助您解決 DLL 問題。以下是其中的部分工具。

  Dependency Walker

  Dependency Walker 工具可以遞迴掃描以尋找程式所使用的所有依賴 DLL。當您在 Dependency Walker 中開啟程式時,Dependency Walker 會執行下列檢查: •Dependency Walker 檢查是否丟失 DLL。

  •Dependency Walker 檢查是否存在無效的程式檔案或 DLL。

  •Dependency Walker 檢查匯入函數和匯出函數是否匹配。

  •Dependency Walker 檢查是否存在循環相依性性錯誤。

  •Dependency Walker 檢查是否存在由於針對另一不同作業系統而無效的模組。

  通過使用 Dependency Walker,您可以記錄程式使用的所有 DLL。這可能有助於避免和更正將來可能發生的 DLL 問題。當您安裝 Microsoft Visual Studio 6.0 時,Dependency Walker 將位於以下目錄中:

  drive\Program Files\Microsoft Visual Studio\Common\Tools

  DLL Universal Problem Solver

  DLL Universal Problem Solver (DUPS) 工具用於審核、比較、記錄和顯示 DLL 資訊。下表說明了組成 DUPS 工具的工具 + 生產力: •Dlister.exe

  該工具 + 生產力枚舉電腦中的所有 DLL,並且將此資訊記錄到一個文字檔或資料庫檔案中。

  •Dcomp.exe

  該工具 + 生產力比較在兩個文字檔中列出的 DLL,併產生包含差異的第三個文字檔。

  •Dtxt2DB.exe

  該工具 + 生產力將通過使用 Dlister.exe 工具 + 生產力和 Dcomp.exe 工具 + 生產力建立的文字檔載入到 dllHell 資料庫中。

  •DlgDtxt2DB.exe

  該工具 + 生產力提供 Dtxt2DB.exe 工具 + 生產力的圖形化使用者介面 (GUI) 版本。

  有關 DUPS 工具的更多資訊,請單擊下面的文章編號,以查看 Microsoft 知識庫中相應的文章:

  247957 (http://support.microsoft.com/kb/247957/) 樣本:使用 DUPS.exe 解決 DLL 相容性問題

  DLL 協助資料庫

  DLL 協助資料庫協助您尋找由 Microsoft 軟體產品安裝的特定版本的 DLL。有關 DLL 協助資料庫的更多資訊,請訪問下面的 Microsoft 網站:

  http://support.microsoft.com/dllhelp/ (http://support.microsoft.com/dllhelp/)

  DLL 開發

  本節介紹您在開發自己的 DLL 時應該考慮的問題和要求。

  DLL 的類型

  當您在應用程式中載入 DLL 時,可以使用兩種連結方法來調用匯出的 DLL 函數。這兩種連結方法是載入時動態連結和運行時動態連結。

  載入時動態連結

  在載入時動態連結中,應用程式像調用本地函數一樣對匯出的 DLL 函數進行顯式調用。要使用載入時動態連結,請在編譯和連結應用程式時提供標頭檔 (.h) 和匯入庫檔案 (.lib)。當您這樣做時,連結器將向系統提供載入 DLL 所需的資訊,並在載入時解析匯出的 DLL 函數的位置。

  運行時動態連結

  在運行時動態連結中,應用程式調用 LoadLibrary 函數或 LoadLibraryEx 函數以在運行時載入 DLL。成功載入 DLL 後,可以使用 GetProcAddress 函數獲得要調用的匯出的 DLL 函數的地址。在使用運行時動態連結時,無需使用匯入庫檔案。

  下面的列表說明了有關何時使用載入時動態連結以及何時使用運行時動態連結的應用程式條件: •啟動效能

  如果應用程式的初始啟動效能很重要,則應使用運行時動態連結。

  •易用性

  在載入時動態連結中,匯出的 DLL 函數類似於本地函數。這使您可以方便地調用這些函數。

  •應用程式邏輯

  在運行時動態連結中,應用程式可以分支,以便按照需要載入不同的模組。在開發多語言版本時,這一點很重要。

  DLL 進入點

  在建立 DLL 時,可以有選擇地指定進入點函數。當進程或線程將它們自身附加到 DLL 或者將它們自身從 DLL 分離時,將調用進入點函數。您可以使用進入點函數根據 DLL 的需要來初始化資料結構或者銷毀資料結構。此外,如果應用程式是多線程的,則可以在進入點函數中使用執行緒區域儲存 (TLS) 來分配各個線程專用的記憶體。下面的代碼是一個 DLL 進入點函數的樣本。

  BOOL APIENTRY DllMain(
  HANDLE hModule, // Handle to DLL module
  DWORD ul_reason_for_call, // Reason for calling function
  LPVOID lpReserved ) // Reserved
  {
  switch ( ul_reason_for_call )
  {
  case DLL_PROCESS_ATTACHED:
  // A process is loading the DLL.
  break;
  case DLL_THREAD_ATTACHED:
  // A process is creating a new thread.
  break;
  case DLL_THREAD_DETACH:
  // A thread exits normally.
  break;
  case DLL_PROCESS_DETACH:
  // A process unloads the DLL.
  break;
  }
  return TRUE;
  }

  當進入點函數返回 FALSE 值時,如果您使用的是載入時動態連結,則應用程式不啟動。如果您使用的是運行時動態連結,則只有個別 DLL 不會載入。

  進入點函數只應執行簡單的初始化任務,不應調用任何其他 DLL 載入函數或終止函數。例如,在進入點函數中,不應直接或間接調用 LoadLibrary 函數或 LoadLibraryEx 函數。此外,不應在進程終止時調用 FreeLibrary 函數。

  注意:在多線程應用程式中,請確保將對 DLL 全域資料的訪問進行同步(安全執行緒),以避免可能的資料損毀。為此,請使用 TLS 為各個線程提供唯一的資料。

  匯出 DLL 函數

  要匯出 DLL 函數,您可以嚮導出的 DLL 函數中添加函數關鍵字,也可以建立模組定義檔案 (.def) 以列出匯出的 DLL 函數。

  要使用函數關鍵字,您必須使用以下關鍵字來聲明要匯出的各個函數:

  __declspec(dllexport)

  要在應用程式中使用匯出的 DLL 函數,您必須使用以下關鍵字來聲明要匯入的各個函數:

  __declspec(dllimport)

  通常情況下,您最好使用一個包含 define 語句和 ifdef 語句的標頭檔,以便分隔匯出語句和匯入語句。

  您還可以使用模組定義檔案來聲明匯出的 DLL 函數。當您使用模組定義檔案時,您不必嚮導出的 DLL 函數中添加函數關鍵字。在模組定義檔案中,您可以聲明 DLL 的 LIBRARY 語句和 EXPORTS 語句。下面的代碼是一個定義檔案的樣本。

  // SampleDLL.def

  //

  LIBRARY "sampleDLL"
  EXPORTS
  HelloWorld
  樣本 DLL 和應用程式
  在 Microsoft Visual C++ 6.0 中,可以通過選擇“Win32 動態連結程式庫”項目類型或“MFC 應用程式嚮導 (dll)”來建立 DLL。
  下面的代碼是一個在 Visual C++ 中通過使用“Win32 動態連結程式庫”項目類型建立的 DLL 的樣本。
  // SampleDLL.cpp
  //
  #include "stdafx.h"
  #define EXPORTING_DLL
  #include "sampleDLL.h"
  BOOL APIENTRY DllMain( HANDLE hModule,
  DWORD ul_reason_for_call,
  LPVOID lpReserved
  )
  {
  return TRUE;
  }
  void HelloWorld()
  {
  MessageBox( NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
  }
  // File: SampleDLL.h
  //
  #ifndef INDLL_H
  #define INDLL_H
  #ifdef EXPORTING_DLL
  extern __declspec(dllexport) void HelloWorld() ;
  #else
  extern __declspec(dllimport) void HelloWorld() ;
  #endif
  #endif

  下面的代碼是一個“Win32 應用程式”項目的樣本,該樣本調用 SampleDLL DLL 中的匯出 DLL 函數。

  // SampleApp.cpp

  //

  #include "stdafx.h"
  #include "sampleDLL.h"
  int APIENTRY WinMain(HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPSTR lpCmdLine,
  int nCmdShow)
  {
  HelloWorld();
  return 0;
  }

  注意:在載入時動態連結中,您必須連結在產生 SampleDLL 項目時建立的 SampleDLL.lib 匯入庫。

  在運行時動態連結中,您應使用與以下代碼類似的代碼來調用 SampleDLL.dll 匯出 DLL 函數。

  ...
  typedef VOID (*DLLPROC) (LPTSTR);
  ...
  HINSTANCE hinstDLL;
  DLLPROC HelloWorld;
  BOOL fFreeDLL;
  hinstDLL = LoadLibrary("sampleDLL.dll");
  if (hinstDLL != NULL)
  {
  HelloWorld = (DLLPROC) GetProcAddress(hinstDLL, "HelloWorld");
  if (HelloWorld != NULL)
  (HelloWorld);
  fFreeDLL = FreeLibrary(hinstDLL);
  }
  ...

  當您編譯和連結 SampleDLL 應用程式時,Windows 作業系統將按照以下順序在下列位置中搜尋 SampleDLL DLL: 1.應用程式檔案夾

  2.當前檔案夾

  3.Windows 系統檔案夾

  注意:GetSystemDirectory 函數返回 Windows 系統檔案夾的路徑。

  4.Windows 檔案夾

  注意:GetWindowsDirectory 函數返回 Windows 檔案夾的路徑。

  .NET Framework 程式集

  在引入 Microsoft .NET 和 .NET Framework 以後,大多數與 DLL 相關聯的問題已經通過使用程式集消除了。程式集是在 .NET 公用語言運行庫 (CLR) 控制之下啟動並執行邏輯功能單元。程式集實際上是作為 .DLL 檔案或 .exe 檔存在的。但是,在內部,程式集與 Microsoft Win32 DLL 大不相同。

  組件檔包含資訊清單、類型中繼資料、Microsoft 中繼語言 (MSIL) 代碼和其他資源。資訊清單包含組件中繼資料,以提供使程式整合為自描述程式集所需的全部資訊。資訊清單中包含以下資訊: •程式集名稱

  •版本資訊

  •地區性資訊

  •強式名稱資訊

  •組件檔列表

  •類型引用資訊

  •引用和依賴程式集資訊

  程式集中包含的 MSIL 代碼是無法直接執行的,需要通過 CLR 來執行。預設情況下,當您建立一個程式集時,該程式集是應用程式專有的。要建立共用組件,需要為該程式集分配強式名稱,然後在全域組件快取中發布該程式集。

  下表說明了程式集的一些功能,並將其與 Win32 DLL 的功能進行了比較: •自描述

  當您建立程式集時,CLR 運行該程式集所需的全部資訊都包含在資訊清單中。資訊清單包含一個依賴程式集列表。因此,CLR 可以維護一組在應用程式中使用的一致的程式集。在 Win32 DLL 中,當您使用共用 DLL 時,無法維護應用程式中使用的一組 DLL 之間的一致性。

  •版本控制

  在資訊清單中,版本資訊由 CLR 記錄和實施。另外,可以通過版本原則來實施版本特定用法。在 Win32 DLL 中,無法由作業系統實施版本控制。相反,您必須確保 DLL 向後相容。

  •並行部署

  程式集支援並行部署。一個應用程式可以使用一個版本的程式集,而另一個應用程式可以使用另一不同版本的程式集。從 Windows 2000 開始,通過將 DLL 放置到應用程式檔案夾中支援並行部署。另外,Windows 檔案保護能夠防止系統 DLL 被未經授權的代理改寫或替換。

  •獨立和隔離

  通過使用程式集開發的應用程式可以是獨立的,並且與電腦中正在啟動並執行其他應用程式隔離。這一特性有助於建立零幹擾安裝。

  •執行

  程式集在資訊清單所提供的並且由 CLR 控制的安全許可權下運行。

  •語言無關性

  可以通過使用任何一種受支援的 .NET 語言來開發程式集。例如,可以在 Microsoft Visual C# 中開發程式集,然後在 Microsoft Visual Basic .NET 項目中使用該程式集。

  參考

  有關 DLL 和 .NET Framework 程式集的更多資訊,請訪問下面的 Microsoft 網站:

  DLL 協助資料庫

  http://support.microsoft.com/dllhelp (http://support.microsoft.com/dllhelp)

  DLL 衝突 (DLL conflicts)

  http://msdn.microsoft.com/library/en-us/dnsetup/html/dlldanger1.asp (http://msdn.microsoft.com/library/en-us/dnsetup/html/dlldanger1.asp)

  在應用程式中實現並行組件共用 (Implementing side-by-side component sharing in applications)

  http://msdn.microsoft.com/library/en-us/dnsetup/html/sidebyside.asp (http://msdn.microsoft.com/library/en-us/dnsetup/html/sidebyside.asp)

  如何產生和維護用於 Windows XP 的獨立應用程式和並行程式集 (How to build and service isolated applications and side-by-side assemblies for Windows XP)

  http://msdn.microsoft.com/library/en-us/dnwxp/html/sidexsidewinxp.asp (http://msdn.microsoft.com/library/en-us/dnwxp/html/sidexsidewinxp.asp)

  使用 .NET Framework 簡化部署和解決 DLL 衝突 (Simplifying deployment and solving DLL conflicts with the .NET Framework)

  http://msdn.microsoft.com/library/en-us/dndotnet/html/dplywithnet.asp (http://msdn.microsoft.com/library/en-us/dndotnet/html/dplywithnet.asp)

  .NET Framework 開發人員指南:程式集

  http://msdn.microsoft.com/library/en-us/cpguide/html/cpconassemblies.asp (http://msdn.microsoft.com/library/en-us/cpguide/html/cpconassemblies.asp)

  建立 Win32 DL (Creating a Win32 DLL)

  http://msdn.microsoft.com/library/en-us/vccore98/html/_core_overview.3a_.creating_a_win32_dll.asp (http://msdn.microsoft.com/library/en-us/vccore98/html/_core_overview.3a_.creating_a_win32_dll.asp)

  運行時動態連結

  http://msdn2.microsoft.com/en-us/library/ms685090.aspx (http://msdn2.microsoft.com/en-us/library/ms685090.aspx)

  執行緒區域儲存 (Thread local storage)

  http://msdn2.microsoft.com/en-us/library/ms686749.aspx



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。