[轉載] VC編寫DLL指南

 

一、DLL的不同類型   

          使用MFC可以生成兩種類型的DLL:MFC擴展DLL和常規DLL。常規DLL又可以分爲動態連接和靜態連接。Visual   C++還可以生成WIN32   DLL,但不是這裏討論的主要對象。   

  1、MFC擴展DLL   

        每個DLL都有某種類型的接口:變量、指針、函數、客戶程序訪問的類。它們的作用是讓客戶程序使用DLL,MFC擴展DLL可以有C++的接口。也就是它可以導出C++類給客戶端。導出的函數可以使用C++/MFC數據類型做參數或返回值,導出一個類時客戶端能創建類對象或者派生這個類。同時,在DLL中也可以使用DLL和MFC。   

        Visual   C++使用的MFC類庫也是保存在一個DLL中,MFC擴展DLL動態連接到MFC代碼庫的DLL,客戶程序也必須要動態連接到MFC代碼庫的DLL。(這裏談到的兩個DLL,一個是我們自己編寫的DLL,一個裝MFC類庫的DLL)現在MFC代碼庫的DLL也存在多個版本,客戶程序和擴展DLL都必須使用相同版本的MFC代碼DLL。所以爲了讓MFC擴展DLL能很好的工作,擴展DLL和客戶程序都必須動態連接到MFC代碼庫DLL。而這個DLL必須在客戶程序運行的計算機上。   

  2、常規DLL   

        使用MFC擴展DLL的一個問題就是DLL僅能和MFC客戶程序一起工作,如果需要一個使用更廣泛的DLL,最好採用常規DLL,因爲它不受MFC的某些限制。常規DLL也有缺點:它不能和客戶程序發送指針或MFC派生類和對象的引用。一句話就是常規DLL和客戶程序的接口不能使用MFC,但在DLL和客戶程序的內部還是可以使用MFC。   

        當在常規DLL的內部使用MFC代碼庫的DLL時,可以是動態連接/靜態連接。如果是動態連接,也就是常規DLL需要的MFC代碼沒有構建到DLL中,這種情況有點和擴展DLL類似,在DLL運行的計算機上必須要MFC代碼庫的DLL。如果是靜態連接,常規DLL裏面已經包含了需要的MFC代碼,這樣DLL的體積將比較大,但它可以在沒有MFC代碼庫DLL的計算機上正常運行。     

 

 二、建立DLL   

          利用Visual   C++提供的嚮導功能可以很容易建立一個不完成任何實質任務的DLL,這裏就不多講了,主要的任務是如何給DLL添加功能,以及在客戶程序中利用這個DLL   

  1、導出類   

        用嚮導建立好框架後,就可以添加需要導出類的.cpp   .h文件到DLL中來,或者用嚮導創建C++   Herder   File/C++   Source   File。爲了能導出這個類,在類聲明的時候要加“_declspec(dllexport)”,如:   

  class   _declspec(dllexport)   CMyClass   

  {   

            ...//聲明   

  }   

  如果創建的MFC擴展DLL,可以使用宏:AFX_EXT_CLASS:   

  class   AFX_EXT_CLASS   CMyClass   

  {   

            ...//聲明   

  }   

  這樣導出類的方法是最簡單的,也可以採用.def文件導出,這裏暫不詳談。   

  2、導出變量、常量、對象   

        很多時候不需要導出一個類,可以讓DLL導出一個變量、常量、對象,導出它們只需要進行簡單的聲明:_declspec(dllexport)   int   MyInt;   

      _declspec(dllexport)   extern   const   COLORREF   MyColor=RGB(0,0,0);   

      _declspec(dllexport)   CRect   rect(10,10,20,20);   

  要導出一個常量時必須使用關鍵字extern,否則會發生連接錯誤。   

  注意:如果客戶程序識別這個類而且有自己的頭文件,則只能導出一個類對象。如果在DLL中創建一個類,客戶程序不使用頭文件就無法識別這個類。   

      當導出一個對象或者變量時,載入DLL的每個客戶程序都有一個自己的拷貝。也就是如果兩個程序使用的是同一個DLL,一個應用程序所做的修改不會影響另一個應用程序。   

      我們在導出的時候只能導出DLL中的全局變量或對象,而不能導出局部的變量和對象,因爲它們過了作用域也就不存在了,那樣DLL就不能正常工作。如:   

  MyFunction()   

  {   

              _declspec(dllexport)   int   MyInt;   

              _declspec(dllexport)   CMyClass   object;   

  }   

  3、導出函數   

  導出函數和導出變量/對象類似,只要把_declspec(dllexport)加到函數原型開始的位置:   

  _declspec(dllexport)   int   MyFunction(int);   

  如果是常規DLL,它將和C寫的程序使用,聲明方式如下:   

  extern   "c"   _declspec(dllexport)   int   MyFunction(int);   

  實現:   

  extern   "c"   _declspec(dllexport)   int   MyFunction(int   x)   

  {   

            ...//操作   

  }   

  如果創建的是動態連接到MFC代碼庫DLL的常規DLL,則必須插入AFX_MANAGE_STATE作爲導出函數的首行,因此定義如下:   

  extern   "c"   _declspec(dllexport)   int   MyFunction(int   x)   

  {   

            AFX_MANAGE_STATE(AfxGetStaticModuleState());   

            ...//操作   

  }   

  有時候爲了安全起見,在每個常規DLL裏都加上,也不會有任何問題,只是在靜態連接的時候這個宏無效而已。這是導出函數的方法,記住只有MFC擴展DLL才能讓參數和返回值使用MFC的數據類型。   

  4、導出指針   

  導出指針的方式如下:   

  _declspec(dllexport)   int   *pint;   

  _declspec(dllexport)   CMyClass   object   =   new   CMyClass;   

  如果聲明的時候同時初始化了指針,就需要找到合適的地方類釋放指針。在擴展DLL中有個函數DllMain()。(注意函數名中的兩個l要是小寫字母),可以在這個函數中處理指針:   

  #   include   "MyClass.h"   

  _declspec(dllexport)   CMyClass   *pobject   =   new   CMyClass;   

  DllMain(HINSTANCE   hInstance,DWORD   dwReason,LPVOID   lpReserved)   

  {   

          if(dwReason   ==   DLL_PROCESS_ATTACH)   

          {   

                  .....//   

          }   

          else   if(dwReason   ==   DLL_PROCESS_DETACH)   

          {   

                  delete   pobject;   

          }   

  }   

  常規DLL有一個從CWinApp派生的類對象處理DLL的開和關,可以使用類嚮導添加InitInstance/ExitInstance函數。   

  int   CMyDllApp::ExitInstance()   

  {   

          delete   pobject;   

          return   CWinApp::ExitInstance();   

  }   

 

  三、在客戶程序中使用DLL   

          編譯一個DLL時將創建兩個文件.dll文件和.lib文件。首先將這兩個文件複製到客戶程序項目的文件夾裏,這裏需要注意DLL和客戶程序的版本問題,儘量使用相同的版本,都使用RELEASE或者都是DEBUG版本。   

        接着就需要在客戶程序中設置LIB文件,打開Project   Settings--->Link--->Object/library   Modules中輸入LIB的文件名和路徑。如:Debug/SampleDll.lib。除了DLL和LIB文件外,客戶程序需要針對導出類、函數、對象和變量的頭文件,現在進行導入添加的關鍵字就是:_declspec(dllimport),如:   

  _declspec(dllimport)   int   MyFunction(int);   

  _declspec(dllimport)   int   MyInt;   

  _declspec(dllimport)   CMyClass   object;   

  extern   "C"   _declspec(dllimport)   int   MyFunction(int);   

  在有的時候爲了導入類,要把相應類的頭文件添加到客戶程序中,不同的是要修改類聲明的標誌:   

  class   _declspec(dllimport)   CMyClass,如果創建的是擴展DLL,兩個位置都是:   

  class   AFX_EXT_CLASS   CMyClass

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章