• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎(chǔ)} {C++ 高級} {C#界面,C++核心算法} {設(shè)計模式} {C#基礎(chǔ)}

            基于Visual C++6.0的DLL編程實現(xiàn)

            基于 Visual C++6.0 DLL 編程實現(xiàn)

            一、前言

              自從微軟推出 16 位的 Windows 操作系統(tǒng)起,此后每種版本的 Windows 操作系統(tǒng)都非常依賴于動態(tài)鏈接庫 (DLL) 中的函數(shù)和數(shù)據(jù),實際上 Windows 操作系統(tǒng)中幾乎所有的內(nèi)容都由 DLL 以一種或另外一種形式代表著,例如顯示的字體和圖標(biāo)存儲在 GDI DLL 中、顯示 Windows 桌面和處理用戶的輸入所需要的代碼被存儲在一個 User DLL 中、 Windows 編程所需要的大量的 API 函數(shù)也被包含在 Kernel DLL 中。

              在 Windows 操作系統(tǒng)中使用 DLL 有很多優(yōu)點,最主要的一點是多個應(yīng)用程序、甚至是不同語言編寫的應(yīng)用程序可以共享一個 DLL 文件,真正實現(xiàn)了資源 " 共享 " ,大大縮小了應(yīng)用程序的執(zhí)行代碼,更加有效的利用了內(nèi)存;使用 DLL 的另一個優(yōu)點是 DLL 文件作為一個單獨的程序模塊,封裝性、獨立性好,在軟件需要升級的時候,開發(fā)人員只需要修改相應(yīng)的 DLL 文件就可以了,而且,當(dāng) DLL 中的函數(shù)改變后,只要不是參數(shù)的改變 , 程序代碼并不需要重新編譯。這在編程時十分有用,大大提高了軟件開發(fā)和維護(hù)的效率。

              既然 DLL 那么重要,所以搞清楚什么是 DLL 、如何在 Windows 操作系統(tǒng)中開發(fā)使用 DLL 是程序開發(fā)人員不得不解決的一個問題。本文針對這些問題,通過一個簡單的例子,即在一個 DLL 中實現(xiàn)比較最大、最小整數(shù)這兩個簡單函數(shù),全面地解析了在 Visual C++ 編譯環(huán)境下編程實現(xiàn) DLL 的過程,文章中所用到的程序代碼在 Windows98 系統(tǒng)、 Visual C++6.0 編譯環(huán)境下通過。

              二、 DLL 的概念

               DLL 是建立在客戶 / 服務(wù)器通信的概念上,包含若干函數(shù)、類或資源的庫文件,函數(shù)和數(shù)據(jù)被存儲在一個 DLL (服務(wù)器)上并由一個或多個客戶導(dǎo)出而使用,這些客戶可以是應(yīng)用程序或者是其它的 DLL DLL 庫不同于靜態(tài)庫,在靜態(tài)庫情況下,函數(shù)和數(shù)據(jù)被編譯進(jìn)一個二進(jìn)制文件(通常擴(kuò)展名為 *.LIB ), Visual C++ 的編譯器在處理程序代碼時將從靜態(tài)庫中恢復(fù)這些函數(shù)和數(shù)據(jù)并把他們和應(yīng)用程序中的其他模塊組合在一起生成可執(zhí)行文件。這個過程稱為 " 靜態(tài)鏈接 " ,此時因為應(yīng)用程序所需的全部內(nèi)容都是從庫中復(fù)制了出來,所以靜態(tài)庫本身并不需要與可執(zhí)行文件一起發(fā)行。

              在動態(tài)庫的情況下,有兩個文件,一個是引入庫( .LIB )文件,一個是 DLL 文件,引入庫文件包含被 DLL 導(dǎo)出的函數(shù)的名稱和位置, DLL 包含實際的函數(shù)和數(shù)據(jù),應(yīng)用程序使用 LIB 文件鏈接到所需要使用的 DLL 文件,庫中的函數(shù)和數(shù)據(jù)并不復(fù)制到可執(zhí)行文件中,因此在應(yīng)用程序的可執(zhí)行文件中,存放的不是被調(diào)用的函數(shù)代碼,而是 DLL 中所要調(diào)用的函數(shù)的內(nèi)存地址,這樣當(dāng)一個或多個應(yīng)用程序運行是再把程序代碼和被調(diào)用的函數(shù)代碼鏈接起來,從而節(jié)省了內(nèi)存資源。從上面的說明可以看出, DLL .LIB 文件必須隨應(yīng)用程序一起發(fā)行,否則應(yīng)用程序?qū)a(chǎn)生錯誤。

              微軟的 Visual C++ 支持三種 DLL ,它們分別是 Non-MFC Dll (非 MFC 動態(tài)庫)、 Regular Dll (常規(guī) DLL )、 Extension Dll (擴(kuò)展 DLL )。 Non-MFC DLL 指的是不用 MFC 的類庫結(jié)構(gòu),直接用 C 語言寫的 DLL ,其導(dǎo)出的函數(shù)是標(biāo)準(zhǔn)的 C 接口,能被非 MFC MFC 編寫的應(yīng)用程序所調(diào)用。 Regular DLL: 和下述的 Extension Dlls 一樣,是用 MFC 類庫編寫的,它的一個明顯的特點是在源文件里有一個繼承 CWinApp 的類(注意:此類 DLL 雖然從 CWinApp 派生,但沒有消息循環(huán)) , 被導(dǎo)出的函數(shù)是 C 函數(shù)、 C++ 類或者 C++ 成員函數(shù)(注意不要把術(shù)語 C++ 類與 MFC 的微軟基礎(chǔ) C++ 類相混淆),調(diào)用常規(guī) DLL 的應(yīng)用程序不必是 MFC 應(yīng)用程序,只要是能調(diào)用類 C 函數(shù)的應(yīng)用程序就可以,它們可以是在 Visual C++ Dephi Visual Basic Borland C 等編譯環(huán)境下利用 DLL 開發(fā)應(yīng)用程序。

              常規(guī) DLL 又可細(xì)分成靜態(tài)鏈接到 MFC 和動態(tài)鏈接到 MFC 上的,這兩種常規(guī) DLL 的區(qū)別將在下面介紹。與常規(guī) DLL 相比,使用擴(kuò)展 DLL 用于導(dǎo)出增強(qiáng) MFC 基礎(chǔ)類的函數(shù)或子類,用這種類型的動態(tài)鏈接庫,可以用來輸出一個從 MFC 所繼承下來的類。

              擴(kuò)展 DLL 是使用 MFC 的動態(tài)鏈接版本所創(chuàng)建的,并且它只被用 MFC 類庫所編寫的應(yīng)用程序所調(diào)用。例如你已經(jīng)創(chuàng)建了一個從 MFC CtoolBar 類的派生類用于創(chuàng)建一個新的工具欄,為了導(dǎo)出這個類,你必須把它放到一個 MFC 擴(kuò)展的 DLL 中。擴(kuò)展 DLL 和常規(guī) DLL 不一樣,它沒有一個從 CWinApp 繼承而來的類的對象,所以,開發(fā)人員必須在 DLL 中的 DllMain 函數(shù)添加初始化代碼和結(jié)束代碼。

            三、動態(tài)鏈接庫的創(chuàng)建

              在 Visual C++6.0 開發(fā)環(huán)境下,打開 FileNewProject 選項,可以選擇 Win32 Dynamic-Link Library MFC AppWizard[dll] 來以不同的方式來創(chuàng)建 Non-MFC Dll Regular Dll Extension Dll 等不同種類的動態(tài)鏈接庫。

               1 Win32 Dynamic-Link Library 方式創(chuàng)建 Non-MFC DLL 動態(tài)鏈接庫

              每一個 DLL 必須有一個入口點,這就象我們用 C 編寫的應(yīng)用程序一樣,必須有一個 WINMAIN 函數(shù)一樣。在 Non-MFC DLL DllMain 是一個缺省的入口函數(shù),你不需要編寫自己的 DLL 入口函數(shù),用這個缺省的入口函數(shù)就能使動態(tài)鏈接庫被調(diào)用時得到正確的初始化。如果應(yīng)用程序的 DLL 需要分配額外的內(nèi)存或資源時,或者說需要對每個進(jìn)程或線程初始化和清除操作時,需要在相應(yīng)的 DLL 工程的 .CPP 文件中對 DllMain() 函數(shù)按照下面的格式書寫。
             

             

            BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
            {
            switch( ul_reason_for_call )
            {
            case DLL_PROCESS_ATTACH:
            .......
            case DLL_THREAD_ATTACH:
            .......
            case DLL_THREAD_DETACH:
            .......
            case DLL_PROCESS_DETACH:
            .......
            }
            return TRUE;
            }

              參數(shù)中, hMoudle 是動態(tài)庫被調(diào)用時所傳遞來的一個指向自己的句柄 ( 實際上,它是指向 _DGROUP 段的一個選擇符 ) ul_reason_for_call 是一個說明動態(tài)庫被調(diào)原因的標(biāo)志,當(dāng)進(jìn)程或線程裝入或卸載動態(tài)鏈接庫的時候,操作系統(tǒng)調(diào)用入口函數(shù),并說明動態(tài)鏈接庫被調(diào)用的原因,它所有的可能值為: DLL_PROCESS_ATTACH: 進(jìn)程被調(diào)用、 DLL_THREAD_ATTACH: 線程被調(diào)用、 DLL_PROCESS_DETACH: 進(jìn)程被停止、 DLL_THREAD_DETACH: 線程被停止; lpReserved 為保留參數(shù)。到此為止, DLL 的入口函數(shù)已經(jīng)寫了,剩下部分的實現(xiàn)也不難,你可以在 DLL 工程中加入你所想要輸出的函數(shù)或變量了。

              我們已經(jīng)知道 DLL 是包含若干個函數(shù)的庫文件,應(yīng)用程序使用 DLL 中的函數(shù)之前,應(yīng)該先導(dǎo)出這些函數(shù),以便供給應(yīng)用程序使用。要導(dǎo)出這些函數(shù)有兩種方法,一是在定義函數(shù)時使用導(dǎo)出關(guān)鍵字 _declspec(dllexport) ,另外一種方法是在創(chuàng)建 DLL 文件時使用模塊定義文件 .Def 。需要讀者注意的是在使用第一種方法的時候,不能使用 DEF 文件。下面通過兩個例子來說明如何使用這兩種方法創(chuàng)建 DLL 文件。

               1 )使用導(dǎo)出函數(shù)關(guān)鍵字 _declspec(dllexport) 創(chuàng)建 MyDll.dll ,該動態(tài)鏈接庫中有兩個函數(shù),分別用來實現(xiàn)得到兩個數(shù)的最大和最小數(shù)。在 MyDll.h MyDLL.cpp 文件中分別輸入如下原代碼:
             

            //MyDLL.h
            extern "C" _declspec(dllexport) int Max(int a, int b);
            extern "C" _declspec(dllexport) int Min(int a, int b);
            //MyDll.cpp
            #i nclude
            #i nclude"MyDll.h"
            int Max(int a, int b)
            {
            if(a>=b)return a;
            else
            return b;
            }
            int Min(int a, int b)
            {
            if(a>=b)return b;
            else
            return a;
            }

              該動態(tài)鏈接庫編譯成功后,打開 MyDll 工程中的 debug 目錄,可以看到 MyDll.dll MyDll.lib 兩個文件。 LIB 文件中包含 DLL 文件名和 DLL 文件中的函數(shù)名等,該 LIB 文件只是對應(yīng)該 DLL 文件的 " 映像文件 " ,與 DLL 文件中, LIB 文件的長度要小的多,在進(jìn)行隱式鏈接 DLL 時要用到它。讀者可能已經(jīng)注意到在 MyDll.h 中有關(guān)鍵字 "extern C" ,它可以使其他編程語言訪問你編寫的 DLL 中的函數(shù)。

               2 )用 .def 文件創(chuàng)建工程 MyDll

              為了用 .def 文件創(chuàng)建 DLL ,請先刪除上個例子創(chuàng)建的工程中的 MyDll.h 文件,保留 MyDll.cpp 并在該文件頭刪除 #i nclude MyDll.h 語句,同時往該工程中加入一個文本文件,命名為 MyDll.def ,再在該文件中加入如下代碼:


            LIBRARY MyDll
            EXPORTS
            Max
            Min

              其中 LIBRARY 語句說明該 def 文件是屬于相應(yīng) DLL 的, EXPORTS 語句下列出要導(dǎo)出的函數(shù)名稱。我們可以在 .def 文件中的導(dǎo)出函數(shù)后加 @n ,如 Max@1 Min@2 ,表示要導(dǎo)出的函數(shù)順序號,在進(jìn)行顯式連時可以用到它。該 DLL 編譯成功后,打開工程中的 Debug 目錄,同樣也會看到 MyDll.dll MyDll.lib 文件。

               2 MFC AppWizard[dll] 方式生成常規(guī) / 擴(kuò)展 DLL

              在 MFC AppWizard[dll] 下生成 DLL 文件又有三種方式,在創(chuàng)建 DLL 是,要根據(jù)實際情況選擇創(chuàng)建 DLL 的方式。一種是常規(guī) DLL 靜態(tài)鏈接到 MFC ,另一種是常規(guī) DLL 動態(tài)鏈接到 MFC 。兩者的區(qū)別是:前者使用的是 MFC 的靜態(tài)鏈接庫,生成的 DLL 文件長度大,一般不使用這種方式,后者使用 MFC 的動態(tài)鏈接庫,生成的 DLL 文件長度小;動態(tài)鏈接到 MFC 的規(guī)則 DLL 所有輸出的函數(shù)應(yīng)該以如下語句開始:

             

            AFX_MANAGE_STATE(AfxGetStaticModuleState( )) // 此語句用來正確地切換 MFC 模塊狀態(tài)

              最后一種是 MFC 擴(kuò)展 DLL ,這種 DLL 特點是用來建立 MFC 的派生類, Dll 只被用 MFC 類庫所編寫的應(yīng)用程序所調(diào)用。前面我們已經(jīng)介紹過, Extension DLLs Regular DLLs 不一樣,它沒有一個從 CWinApp 繼承而來的類的對象,編譯器默認(rèn)了一個 DLL 入口函數(shù) DLLMain() 作為對 DLL 的初始化,你可以在此函數(shù)中實現(xiàn)初始化 , 代碼如下:
             

            BOOL WINAPI APIENTRY DLLMain(HINSTANCE hinstDll DWORD reason LPVOID flmpload)
            {
            switch(reason)
            {
            ……………//
            初始化代碼;

            }
            return true;
            }

              參數(shù) hinstDll 存放 DLL 的句柄,參數(shù) reason 指明調(diào)用函數(shù)的原因, lpReserved 是一個被系統(tǒng)所保留的參數(shù)。對于隱式鏈接是一個非零值,對于顯式鏈接值是零。

              在 MFC 下建立 DLL 文件,會自動生成 def 文件框架,其它與建立傳統(tǒng)的 Non-MFC DLL 沒有什么區(qū)別,只要在相應(yīng)的頭文件寫入關(guān)鍵字 _declspec(dllexport) 函數(shù)類型和函數(shù)名等,或在生成的 def 文件中 EXPORTS 下輸入函數(shù)名就可以了。需要注意的是在向其它開發(fā)人員分發(fā) MFC 擴(kuò)展 DLL 時,不要忘記提供描述 DLL 中類的頭文件以及相應(yīng)的 .LIB 文件和 DLL 本身,此后開發(fā)人員就能充分利用你開發(fā)的擴(kuò)展 DLL 了。

             應(yīng)用程序使用DLL可以采用兩種方式:一種是隱式鏈接,另一種是顯式鏈接。在使用DLL之前首先要知道DLL中函數(shù)的結(jié)構(gòu)信息。Visual C++6.0VCin目錄下提供了一個名為Dumpbin.exe的小程序,用它可以查看DLL文件中的函數(shù)結(jié)構(gòu)。另外,Windows系統(tǒng)將遵循下面的搜索順序來定位DLL 1.包含EXE文件的目錄,2.進(jìn)程的當(dāng)前工作目錄, 3Windows系統(tǒng)目錄, 4Windows目錄,5.列在Path環(huán)境變量中的一系列目錄。

              1.隱式鏈接

              隱式鏈接就是在程序開始執(zhí)行時就將DLL文件加載到應(yīng)用程序當(dāng)中。實現(xiàn)隱式鏈接很容易,只要將導(dǎo)入函數(shù)關(guān)鍵字_declspec(dllimport)函數(shù)名等寫到應(yīng)用程序相應(yīng)的頭文件中就可以了。下面的例子通過隱式鏈接調(diào)用MyDll.dll庫中的Min函數(shù)。首先生成一個項目為TestDll,在DllTest.hDllTest.cpp文件中分別輸入如下代碼:
             

             

            //Dlltest.h
            #pragma comment(lib
            "MyDll.lib")
            extern "C"_declspec(dllimport) int Max(int a,int b);
            extern "C"_declspec(dllimport) int Min(int a,int b);
            //TestDll.cpp
            #i nclude
            #i nclude"Dlltest.h"
            void main()
            {int a;
            a=min(8,10)
            printf("
            比較的結(jié)果為 %d " a);
            }
             

              在創(chuàng)建 DllTest.exe 文件之前,要先將 MyDll.dll MyDll.lib 拷貝到當(dāng)前工程所在的目錄下面,也可以拷貝到 windows System 目錄下。如果 DLL 使用的是 def 文件,要刪除 TestDll.h 文件中關(guān)鍵字 extern "C" TestDll.h 文件中的關(guān)鍵字 Progam commit 是要 Visual C+ 的編譯器在 link 時,鏈接到 MyDll.lib 文件,當(dāng)然,開發(fā)人員也可以不使用 #pragma comment(lib "MyDll.lib") 語句,而直接在工程的 Setting->Link 頁的 Object/Moduls 欄填入 MyDll.lib 既可。

               2 .顯式鏈接

              顯式鏈接是應(yīng)用程序在執(zhí)行過程中隨時可以加載 DLL 文件,也可以隨時卸載 DLL 文件,這是隱式鏈接所無法作到的,所以顯式鏈接具有更好的靈活性,對于解釋性語言更為合適。不過實現(xiàn)顯式鏈接要麻煩一些。在應(yīng)用程序中用 LoadLibrary MFC 提供的 AfxLoadLibrary 顯式的將自己所做的動態(tài)鏈接庫調(diào)進(jìn)來,動態(tài)鏈接庫的文件名即是上述兩個函數(shù)的參數(shù),此后再用 GetProcAddress() 獲取想要引入的函數(shù)。自此,你就可以象使用如同在應(yīng)用程序自定義的函數(shù)一樣來調(diào)用此引入函數(shù)了。在應(yīng)用程序退出之前,應(yīng)該用 FreeLibrary MFC 提供的 AfxFreeLibrary 釋放動態(tài)鏈接庫。下面是通過顯式鏈接調(diào)用 DLL 中的 Max 函數(shù)的例子。
             

            #i nclude
            #i nclude
            void main(void)
            {
            typedef int(*pMax)(int a,int b);
            typedef int(*pMin)(int a,int b);
            HINSTANCE hDLL;
            PMax Max
            HDLL=LoadLibrary("MyDll.dll");//
            加載動態(tài)鏈接庫 MyDll.dll 文件;
            Max=(pMax)GetProcAddress(hDLL,"Max");
            A=Max(5,8);
            Printf("
            比較的結(jié)果為 %d " a);
            FreeLibrary(hDLL);//
            卸載 MyDll.dll 文件;
            }

              在上例中使用類型定義關(guān)鍵字 typedef ,定義指向和 DLL 中相同的函數(shù)原型指針,然后通過 LoadLibray() DLL 加載到當(dāng)前的應(yīng)用程序中并返回當(dāng)前 DLL 文件的句柄,然后通過 GetProcAddress() 函數(shù)獲取導(dǎo)入到應(yīng)用程序中的函數(shù)指針,函數(shù)調(diào)用完畢后,使用 FreeLibrary() 卸載 DLL 文件。在編譯程序之前,首先要將 DLL 文件拷貝到工程所在的目錄或 Windows 系統(tǒng)目錄下。

              使用顯式鏈接應(yīng)用程序編譯時不需要使用相應(yīng)的 Lib 文件。另外,使用 GetProcAddress() 函數(shù)時,可以利用 MAKEINTRESOURCE() 函數(shù)直接使用 DLL 中函數(shù)出現(xiàn)的順序號,如將 GetProcAddress(hDLL,"Min") 改為 GetProcAddress(hDLL, MAKEINTRESOURCE(2)) (函數(shù) Min() DLL 中的順序號是 2 ),這樣調(diào)用 DLL 中的函數(shù)速度很快,但是要記住函數(shù)的使用序號,否則會發(fā)生錯誤。

            posted on 2006-07-24 19:18 夢在天涯 閱讀(2488) 評論(2)  編輯 收藏 引用 所屬分類: CPlusPlus

            評論

            # re: 基于Visual C++6.0的DLL編程實現(xiàn) 2007-07-09 11:25 冬冬壞家伙

            大哥,我是剛?cè)绱髮W(xué),學(xué)習(xí)C++的一個新手。

            有個問題問下,我有個課程設(shè)計完成不了,想請大蝦們幫幫忙。

            課程題目是:足球俱樂部管理系統(tǒng)。

            求助...!!!  回復(fù)  更多評論   

            # re: 基于Visual C++6.0的DLL編程實現(xiàn) 2010-01-16 19:58 Harry.L

            “從上面的說明可以看出, DLL 和 .LIB 文件必須隨應(yīng)用程序一起發(fā)行,否則應(yīng)用程序?qū)a(chǎn)生錯誤。”這個說法不準(zhǔn)確吧!除了DLL文件外,其對應(yīng)的.LIB文件不必隨應(yīng)用程序一起發(fā)行。  回復(fù)  更多評論   

            公告

            EMail:itech001#126.com

            導(dǎo)航

            統(tǒng)計

            • 隨筆 - 461
            • 文章 - 4
            • 評論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1811204
            • 排名 - 5

            最新評論

            閱讀排行榜

            国产福利电影一区二区三区,免费久久久久久久精 | 久久涩综合| 无码任你躁久久久久久久| 国产精品久久久香蕉| 国内精品久久久久久99| 久久精品国产福利国产琪琪| 热久久视久久精品18| 国产精品久久自在自线观看| 久久大香萑太香蕉av| 人人狠狠综合久久亚洲88| 欧美伊人久久大香线蕉综合| 色综合久久久久网| 一本色综合网久久| 亚洲国产高清精品线久久| 国产精品久久久久影院嫩草| 久久无码专区国产精品发布| 亚洲国产成人久久精品影视| 亚洲国产精品高清久久久| 性欧美大战久久久久久久 | 久久婷婷午色综合夜啪| 欧美亚洲另类久久综合| 无码国内精品久久人妻| 色婷婷综合久久久久中文字幕| 久久夜色精品国产网站| 久久精品国产亚洲AV久| 久久国产成人午夜AV影院| 国产精品久久免费| 国产精品一久久香蕉国产线看| 久久无码中文字幕东京热| 久久综合五月丁香久久激情| AAA级久久久精品无码区| 久久这里只有精品首页| 99久久免费国产精品热| 99久久精品国产免看国产一区| 久久亚洲精品国产精品| 久久夜色精品国产噜噜噜亚洲AV| 97视频久久久| 色综合久久综合中文综合网| 久久亚洲春色中文字幕久久久| 色88久久久久高潮综合影院| 欧美午夜精品久久久久免费视|