DLL入門系列二

來源:互聯網
上載者:User

為了便於學習,本系列文章轉載於http://www.cppblog.com/suiaiguo/archive/2009/07/20/90619.html,如果需要轉載,請註明轉載原網址。

上文我簡單的介紹了如何建立一個簡單DLL,下面再我簡單的介紹一下如何使用一個DLL。當一個DLL被產生後,它建立了一個.dll檔案和一個.lib檔案;這兩個都是你需要的。要使用DLL,就需要載入這個DLL。

隱式連結

這裡有兩個方法來載入一個DLL;一個方法是捷徑另一個則相比要複雜些。捷徑是只連結到你.lib 檔案並將.dll檔案置入你的新項目的路徑中去。因此,建立一個新的空的Win32控制台項目並添加一個源檔案。將你做的DLL放入你的新項目相同的目錄下。

 

#include "stdafx.h"
#include "DLLSample.h"

#pragma comment(lib, "DLLSample.lib") //你也可以在項目屬性中設定庫的連結

int main()
{
        TestDLL(123);
        return(1);
}

 

這就是載入一個DLL的簡單方法。

顯式連結

痛點的載入DLL的方法稍微有點複雜。你將需要函數指標和一些Windows函數。但是,通過這種載入DLLs的方法,你不需要DLL的.lib或標頭檔,而只需要DLL。

 

#include <iostream>
#include <windows.h>
typedef void (*DLLFunc)(int);
int main()
{
        DLLFunc dllFunc;
        HINSTANCE hInstLibrary = LoadLibrary("DLLSample.dll");

        if (hInstLibrary == NULL)
        {
         FreeLibrary(hInstLibrary);
        }
        dllFunc = (DLLFunc)GetProcAddress(hInstLibrary, "TestDLL");
        if (dllFunc == NULL)
        {
         FreeLibrary(hInstLibrary);
        }
        dllFunc(123);
        std::cin.get();
        FreeLibrary(hInstLibrary);
        return(1);
}

 

     
首先你會注意到:這裡包括進了檔案“windows.h”同時移走了“DLLSample.h”。原因很簡單:因為windows.h包含了一些Windows函數,當然你現在將只需要其中幾個而已。它也包含了一些將會用到的Windows特定變數。你可以去掉DLL的標頭檔(DLLSample.h)因為-如我前面所說-當你使用這個方法載入DLL時你並不需要它。

下面你會看到:下面的一句代碼:

typedef void (*DLLFunc)(int);
     
這是一個函數指標類型的定義。指向一個函數是一個int型的參數,傳回值為void類型。

一個HINSTANCE是一個Windows資料類型:是一個執行個體的控制代碼;在此情況下,這個執行個體將是這個DLL。你可以通過使用函數LoadLibrary()獲得DLL的執行個體,它獲得一個名稱作為參數。在調用LoadLibrary函數後,你必需查看一下函數返回是否成功。你可以通過檢查HINSTANCE是否等於NULL(在Windows.h中定義為0或Windows.h包含的一個標頭檔)來查看其是否成功。如果其等於NULL,該控制代碼將是無效的,並且你必需釋放這個庫。換句話說,你必需釋放DLL獲得的記憶體。如果函數返回成功,你的HINSTANCE就包含了指向DLL的控制代碼。

一旦你獲得了指向DLL的控制代碼,你現在可以從DLL中重新獲得函數。為了這樣作,你必須使用函數GetProcAddress(),它將DLL的控制代碼(你可以使用HINSTANCE)和函數的名稱作為參數。你可以讓函數指標獲得由GetProcAddress()返回的值,同時你必需將GetProcAddress()轉換為那個函數定義的函數指標。舉個例子,對於Add()函數,你必需將GetProcAddress()轉換為AddFunc;這就是它知道參數及傳回值的原因。現在,最好先確定函數指標是否等於NULL以及它們擁有DLL的函數。這隻是一個簡單的if語句;如果其中一個等於NULL,你必需如前所述釋放庫。

一旦函數指標擁有DLL的函數,你現在就可以使用它們了,但是這裡有一個需要注意的地方:你不能使用函數的實際名稱;你必需使用函數指標來調用它們。在那以後,所有你需要做的是釋放庫如此而已。

模組控制代碼

進程中的每個DLL模組被全域唯一的32位元組的HINSTANCE控制代碼標識。進程自己還有一個HINSTANCE控制代碼。所有這些模組控制代碼都只有在特定的進程內部有效,它們代表了DLL或EXE模組在進程虛擬空間中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,這個兩種類型可以替換使用。進程模組控制代碼幾乎總是等於0x400000,而DLL模組的載入地址的預設控制代碼是0x10000000。如果程式同時使用了幾個DLL模組,每一個都會有不同的HINSTANCE值。這是因為在建立DLL檔案時指定了不同的基地址,或者是因為載入程式對DLL代碼進行了重定位。
模組控制代碼對於載入資源特別重要。Win32 的FindResource函數中帶有一個HINSTANCE參數。EXE和DLL都有其自己的資源。如果應用程式需要來自於DLL的資源,就將此參數指定為DLL的模組控制代碼。如果需要EXE檔案中包含的資源,就指定EXE的模組控制代碼。
但是在使用這些控制代碼之前存在一個問題,你怎樣得到它們呢?如果需要得到EXE模組控制代碼,調用帶有Null參數的Win32函數GetModuleHandle;如果需要DLL模組控制代碼,就調用以DLL檔案名稱為參數的Win32函數GetModuleHandle。

應用程式怎樣找到DLL檔案

如果應用程式使用LoadLibrary顯式連結,那麼在這個函數的參數中可以指定DLL檔案的完整路徑。如果不指定路徑,或是進行隱式連結,Windows將遵循下面的搜尋順序來定位DLL:
1. 包含EXE檔案的目錄,
2. 進程的當前工作目錄,
3. Windows系統目錄,
4. Windows目錄,
5. 列在Path環境變數中的一系列目錄。
這裡有一個很容易發生錯誤的陷阱。如果你使用VC++進行項目開發,並且為DLL模組專門建立了一個項目,然後將產生的DLL檔案拷貝到系統目錄下,從應用程式中調用DLL模組。到目前為止,一切正常。接下來對DLL模組做了一些修改後重建了新的DLL檔案,但你忘記將新的DLL檔案拷貝到系統目錄下。下一次當你運行應用程式時,它仍載入了老版本的DLL檔案,這可要當心!

調試DLL程式

Microsoft 的VC++是開發與測試DLL的有效工具,只需從DLL項目中運行偵錯工具即可。當你第一次這樣操作時,偵錯工具會向你詢問EXE檔案的路徑。此後每次在偵錯工具中運行DLL時,偵錯工具會自動載入該EXE檔案。然後該EXE檔案用上面的搜尋序列發現DLL檔案,這意味著你必須設定Path環境變數讓其包含DLL檔案的磁碟路徑,或者也可以將DLL檔案拷貝到搜尋序列中的目錄路徑下。
或者當你調試EXE程式時,在Project Setting中,將Debug選項卡中的Category設定為Additional DLLs。就可以同時調試EXE和它調用的DLL(當然,你需要有DLL的原始碼)了。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.