Windows 動態連結程式庫編程

來源:互聯網
上載者:User

標籤:因此   bsp   用戶端   res   windows編程   名稱   char   互斥   客戶   

Windows 動態連結程式庫編程  

1、介紹

Windows作業系統是應用最關的作業系統,因此動態連結程式庫也為程式員所熟悉,即使對於普通的使用者來說,很多時候也會碰到.dll結尾的檔案,這就是動態連結程式庫檔案。Windows下的動態連結程式庫可以通過參考標頭檔和.lib庫檔案進行編譯,從而使得動態連結程式庫隱式地被使用;也可以使用LoadLibrary、GetProcAddress等函數來顯式調用動態連結程式庫。

2、文法、匯入匯出

在Windows編程中,對於要使用或被使用的函數或者變數,需要使用 __declspec 關鍵字來聲明,以告訴編譯器該變數或函數不是普通的變數或函數,而是一個動態連結程式庫的介面屬性。

如果定義一個要被其他代碼使用的函數,可以寫成:
__declspec( dllexport ) int add(int a, int b);

如果在該代碼中,打算使用另外一個程式中的變數,則可以寫成:
__declspec( dllimport ) char *name;

動態連結程式庫通常包含一系列供其他程式使用函數,因此 declspec( dllexport ) 文法形式最為常用。如果動態庫需要其他程式中的定義的全域變數,則需要在其他程式中使用匯出該變數,在動態連結程式庫中則需要使用 extern declspec( dllexport ) 將該變數聲明為外部變數以便使用。

3、連結方式

可以以下列兩種方式之一連結到(或載入)DLL:

隱式連結
顯式連結

隱式連結有時稱為靜態載入或載入時動態連結。顯式連結有時稱為動態載入或運行時動態連結。在隱式連結下,使用 DLL 的可執行檔連結到該 DLL 的建立者所提供的匯入庫(.lib 檔案)。使用 DLL 的可執行檔載入時,作業系統載入此 DLL。用戶端可執行檔調用 DLL 的匯出函數,就好像這些函數包含在可執行檔內一樣。

在顯式連結下,使用 DLL 的可執行檔必須進行函數調用以明確式載入和卸載該 DLL,並訪問該 DLL 的匯出函數。用戶端可執行檔必須通過函數指標調用匯出函數。可執行檔對兩種連結方法可以使用同一個 DLL。另外,由於一個可執行檔可隱式連結到某個 DLL,而另一個可顯式附加到此 DLL,故這些機制不是互斥的。

4、隱式連結

隱式連結動態連結程式庫比較簡單,不予詳述。

5、顯式連結API函數

顯式連結主要涉及到3個API函數( LoadLibrary , GetProcAddress 和 FreeLibrary ),要使用這些函數包含windows.h標頭檔即可。

(1)HINSTANCE LoadLibrary(LPCSTR lpLibFileName);

該函數用來載入指定動態庫檔案,並且返回控制代碼。

參數lpLibFileName為動態連結程式庫的名稱。Windows 首先搜尋“已知 DLL”,如 Kernel32.dll 和 User32.dll。然後按下列順序搜尋 DLL:

1、當前進程的可執行模組所在的目錄。
2、目前的目錄。
3、Windows 系統目錄。GetSystemDirectory 函數檢索此目錄的路徑。
4、Windows 目錄。GetWindowsDirectory 函數檢索此目錄的路徑。
5、PATH 環境變數中列出的目錄。

(2)FARPROC GetProcAddress (HMODULE hModule, LPCSTR lpProcName);

函數GetProcAddress 用來擷取 DLL 匯出函數的地址。返回由lpProcName指定的變數或函數指標。

參數hModule為已經載入的動態庫檔案的控制代碼。

參數lpProcName為要調用的變數或函數名稱。

(3)BOOL FreeLibrary(HMODULE hModule);
從記憶體中釋放hModule所代表的動態連結程式庫。

(4)如果發生錯誤,可以調用GetLastError()函數或去錯誤碼。

6、顯示連結舉例

(1)動態庫檔案代碼:dll_demo.c

#include <stdio.h>

__declspec( dllexport ) int add(int a, int b)
{
printf("calling add\n");
return a + b;
}

該檔案中的add()Function Compute兩個整數之和,並且返回之前列印提示字串。函數使用 __declspec( dllexport ) 文法來說明函數add(int a, int b)要被匯出。

(2)用戶端案例代碼:main.c

#include <stdio.h>
#include <windows.h>

int main (int argc, char *argv[])
{
int a = 10, b = 20;
int c = 0;
HINSTANCE   hInstLibrary   =   NULL;
int (*add)();

printf ("Load DLL file\n");
if ((hInstLibrary = LoadLibrary(L"dll_demo.dll")) == NULL)
{
   printf ("***LoadLibrary ERROR: %d.\n", GetLastError());
   return 1;
}
if((add = (int (*)())GetProcAddress(hInstLibrary, "add")) == NULL) {
   printf ("***GetProcAddress ERROR: %d.\n", GetLastError());
   return 1;
}

c = add(a, b);
printf("%d + %d = %d\n", a, b, c);

FreeLibrary(hInstLibrary);
return 0;
}

程式利用LoadLibrary函數載入動態連結dll_demo.dll,利用FreeLibrary關閉控制代碼,利用GetLastError()擷取錯誤碼,利用GetProcAddress定位共用庫中的add函數,然後調用該函數執行加法計算,並列印結果。

(3)編譯與運行

編譯共用庫:

在VS.Net中建立一個動態連結程式庫項目,名稱為dll_demo,加入檔案dll_demo.c,編譯後產生dll_demo.dll檔案。

編譯案例程式:

在VS.Net中建立一個動態連結程式庫項目,名稱為dll_main,加入檔案main.c,編譯後產生dll_main.exe可以執行檔案。

運行:

將 dll_demo.dll 和 dll_main.exe 放在同一個目錄下,然後雙擊運行 dll_main.exe。

輸出:

Load DLL file
calling add
10 + 20 = 30

7、調用動態連結程式庫中的變數

也可以使用動態連結程式庫中的變數。例如,在動態連結程式庫中定義:

__declspec( dllexport ) int num = 100;

那麼可以在案例程式中這樣調用:

int *d;
d = (int *)GetProcAddress(hInstLibrary, "num");
printf("num = %d\n", *d);

Windows 動態連結程式庫編程

相關文章

聯繫我們

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

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

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.