| 導購 | 订阅 | 在线投稿
分享
 
 
 

VC++動態鏈接庫編程之MFC擴展 DLL

來源:互聯網網民  2008-06-01 02:07:07  評論

DLL類型入口函數 非 MFC DLL 編程者提供DllMain函數 MFC規則 DLL CWinApp對象的InitInstance 和 ExitInstance MFC擴展 DLL MFC DLL向導生成DllMain 函數

對于MFC擴展DLL,系統會自動在工程中添加如下表所示的宏,這些宏爲DLL和應用程序的編寫提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA這樣的宏,在DLL和應用程序中將具有不同的定義,這取決于_AFXEXT宏是否被定義。這使得在DLL和應用程序中,使用統一的一個宏就可以表示出輸出和輸入的不同意思。在DLL中,表示輸出(因爲_AFXEXT被定義,通常是在編譯器的標識參數中指定/D_AFXEXT);在應用程序中,則表示輸入(_AFXEXT沒有定義)。

宏定義 AFX_CLASS_IMPORT __declspec(dlleXPort) AFX_API_IMPORT __declspec(dllexport) AFX_DATA_IMPORT __declspec(dllexport) AFX_CLASS_EXPORT __declspec(dllexport) AFX_API_EXPORT __declspec(dllexport) AFX_DATA_EXPORT __declspec(dllexport) AFX_EXT_CLASS #ifdef _AFXEXT

AFX_CLASS_EXPORT

#else

AFX_CLASS_IMPORT AFX_EXT_API #ifdef _AFXEXT

AFX_API_EXPORT

#else

AFX_API_IMPORT AFX_EXT_DATA #ifdef _AFXEXT

AFX_DATA_EXPORT

#else

AFX_DATA_IMPORT

6.2 MFC擴展DLL導出MFC派生類

在這個例子中,我們將産生一個名爲「ExtDll」的MFC擴展DLL工程,在這個DLL中導出一個對話框類,這個對話框類派生自MFC類CDialog。

使用MFC向導生成MFC擴展DLL時,系統會自動添加如下代碼:

static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };

extern "C" int APIENTRY

DllMain( HINSTANCE hInstance, DWord dwReason, LPVOID lPReserved )

{

// Remove this if you use lpReserved

UNREFERENCED_PARAMETER( lpReserved );

//說明:lpReserved是一個被系統所保留的參數,對于隱式鏈接是一個非零值,對于顯式鏈接值是零

if (dwReason == DLL_PROCESS_ATTACH)

{

TRACE0( "EXTDLL.DLL Initializing!\n" );

// Extension DLL one-time initialization

if ( !AfxInitExtensionModule( ExtDllDLL, hInstance ))

return 0;

// Insert this DLL into the resource chain

new CDynLinkLibrary( ExtDllDLL );

}

else if (dwReason == DLL_PROCESS_DETACH)

{

TRACE0( "EXTDLL.DLL Terminating!\n" );

// Terminate the library before destrUCtors are called

AfxTermExtensionModule( ExtDllDLL );

}

return 1; // ok

}

這一段代碼含義晦澀,我們需要對其進行解讀:

(1)上述代碼完成MFC擴展DLL的初始化和終止處理;

(2)初始化期間所創建的 CDynLinkLibrary 對象使MFC擴展 DLL 可以將 DLL中的CRuntimeClass 對象或資源導出到應用程序;

(3)AfxInitExtensionModule函數捕捉模塊的CRuntimeClass 結構和在創建 CDynLinkLibrary 對象時使用的對象工廠(COleObjectFactory 對象);

(4)AfxTermExtensionModule函數使 MFC 得以在每個進程與擴展 DLL 分離時(進程退出或使用AfxFreeLibrary卸載DLL時)清除擴展 DLL;

(5)第一條語句static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };定義了一個AFX_EXTENSION_MODULE類的靜態全局對象,AFX_EXTENSION_MODULE的定義如下:

struct AFX_EXTENSION_MODULE

{

BOOL bInitialized;

HMODULE hModule;

HMODULE hResource;

CRuntimeClass* pFirstSharedClass;

COleObjectFactory* pFirstSharedFactory;

};

由AFX_EXTENSION_MODULE的定義我們可以更好的理解(2)、(3)、(4)點。

在資源編輯器中添加一個如圖15所示的對話框,並使用MFC類向導爲其添加一個對應的類CExtDialog,系統自動添加了ExtDialog.h和ExtDialog.cpp兩個頭文件。

VC++動態鏈接庫編程之MFC擴展 DLL

圖15 MFC擴展DLL中的對話框

修改ExtDialog.h中CExtDialog類的聲明爲:

class AFX_EXT_CLASS CExtDialog : public CDialog

{

public:

CExtDialog( CWnd* pParent = NULL );

enum { IDD = IDD_DLL_DIALOG };

protected:

virtual void DoDataExchange( CDataExchange* pDX );

DECLARE_MESSAGE_MAP()

};

這其中最主要的改變是我們在class AFX_EXT_CLASS CExtDialog語句中添加了「AFX_EXT_CLASS」宏,則使得DLL中的CExtDialog類被導出。

6.3 MFC擴展DLL的加載

6.3.1 隱式加載

我們在6.2工程所在的工作區中添加一個LoadExtDllDlg工程,用于演示MFC擴展DLL的加載。在LoadExtDllDlg工程中添加一個如圖16所示的對話框,這個對話框上包括一個「調用DLL」按鈕。

VC++動態鏈接庫編程之MFC擴展 DLL

圖16 MFC擴展DLL調用工程中的對話框

在與圖16對應對話框類實現文件的頭部添加:

// LoadExtDllDlg.cpp : implementation file

//

#include "..\ExtDialog.h"

#pragma comment( lib, "ExtDll.lib" )

而「調用DLL」按鈕的單擊事件的消息處理函數爲:

void CLoadExtDllDlg::OnDllcallButton()

{

CExtDialog extDialog;

extDialog.DoModal();

}

當我們單擊「調用DLL」的時候,彈出了如圖15的對話框。

爲提供給用戶隱式加載(MFC擴展DLL一般使用隱式加載,具體原因見下節),MFC擴展DLL需要提供三個文件:

(1)描述DLL中擴展類的頭文件;

(2)與動態鏈接庫對應的.LIB文件;

(3)動態鏈接庫.DLL文件本身。

有了這三個文件,應用程序的開發者才可充分利用MFC擴展DLL。

6.3.2 顯示加載

顯示加載MFC擴展DLL應使用MFC全局函數AfxLoadLibrary而不是WIN32 API中的LoadLibrary。AfxLoadLibrary 最終也調用了 LoadLibrary這個API,但是在調用之前進行了線程同步的處理。

AfxLoadLibrary 的函數原型與 LoadLibrary完全相同,爲:

HINSTANCE AFXAPI AfxLoadLibrary( LPCTSTR lpszModuleName );

與之相對應的是,MFC 應用程序應使用AfxFreeLibrary 而非FreeLibrary 卸載MFC擴展DLL。AfxFreeLibrary的函數原型也與 FreeLibrary完全相同,爲:

BOOL AFXAPI AfxFreeLibrary( HINSTANCE hInstLib );

假如我們把上例中的「調用DLL」按鈕單擊事件的消息處理函數改爲:

void CLoadExtDllDlg::OnDllcallButton()

{

HINSTANCE hDll = AfxLoadLibrary( "ExtDll.dll" );

if(NULL == hDll)

{

AfxMessageBox( "MFC擴展DLL動態加載失敗" );

return;

}

CExtDialog extDialog;

extDialog.DoModal();

AfxFreeLibrary(hDll);

}

則工程會出現link錯誤:

LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall CExtDialog::~CExtDialog(void)" (__imp_??1CExtDialogUAE@XZ)

LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall CExtDialog::CExtDialog(class CWnd *)" (__imp_??0CExtDialogQAE@PAVCWnd@Z)

提示CExtDialog的構造函數和析構函數均無法找到!是的,對于派生MFC類的MFC擴展DLL,當我們要在應用程序中使用DLL中定義的派生類時,我們不宜使用動態加載DLL的方法。

6.4 MFC擴展DLL加載MFC擴展DLL

我們可以在MFC擴展DLL中再次使用MFC擴展DLL,但是,由于在兩個DLL中對于AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA宏的定義都是輸出,這會導致調用的時候出現問題。

我們將會在調用MFC擴展DLL的DLL中看到link錯誤:

error LNK2001: unresolved external symbol ….......

因此,在調用MFC擴展DLL的MFC擴展DLL中,在包含被調用DLL的頭文件之前,需要臨時重新定義AFX_EXT_CLASS的值。下面的例子顯示了如何實現:

//臨時改變宏的含義「輸出」爲「輸入」

#undef AFX_EXT_CLASS

#undef AFX_EXT_API

#undef AFX_EXT_DATA

#define AFX_EXT_CLASS AFX_CLASS_IMPORT

#define AFX_EXT_API AFX_API_IMPORT

#define AFX_EXT_DATA AFX_DATA_IMPORT

//包含被調用MFC擴展DLL的頭文件

#include "CalledDLL.h"

//恢複宏的含義爲輸出

#undef AFX_EXT_CLASS

#undef AFX_EXT_API

#undef AFX_EXT_DATA

#define AFX_EXT_CLASS AFX_CLASS_EXPORT

#define AFX_EXT_API AFX_API_EXPORT

#define AFX_EXT_DATA AFX_DATA_EXPORT

6.5 MFC擴展DLL導出函數和變量

MFC擴展DLL導出函數和變量的方法也十分簡單,下面我們給出一個簡單的例子。

我們在MFC向導生成的MFC擴展DLL工程中添加gobal.h和global.cpp兩個文件:

//global.h:MFC擴展DLL導出變量和函數的聲明

extern "C"

{

int AFX_EXT_DATA total; //導出變量

int AFX_EXT_API add( int x, int y ); //導出函數

}

//global.cpp:MFC擴展DLL導出變量和函數定義

#include "StdAfx.h"

#include "global.h"

extern "C" int total;

int add(int x,int y)

{

total = x + y;

return total;

}

編寫一個簡單的控制台程序來調用這個MFC擴展DLL:

#include

#include 單擊此處下載本工程)。

我們知道static控件所對應的CStatic類不具備設置背景和文本顔色的接口,這使得我們不能在對話框或其它用戶界面上自由靈活地修改static控件的顔色風格,因此我們需要一個提供了SetBackColor和SetTextColor接口的CStatic派生類CMultiColorStatic。

這個類的聲明如下:

class AFX_EXT_CLASS CMultiColorStatic : public CStatic

{

// Construction

public:

CMultiColorStatic();

virtual ~CMultiColorStatic();

// Attributes

protected:

CString m_strCaption;

COLORREF m_BackColor;

COLORREF m_TextColor;

// Operations

public:

void SetTextColor( COLORREF TextColor );

void SetBackColor( COLORREF BackColor );

void SetCaption( CString strCaption );

// Generated message map functions

protected:

afx_msg void OnPaint();

DECLARE_MESSAGE_MAP()

};

在這個類的實現文件中,我們需要爲它提供WM_PAINT消息的處理函數(這是因爲顔色的設置依靠于WM_PAINT消息):

BEGIN_MESSAGE_MAP(CMultiColorStatic, CStatic)

//{{AFX_MSG_MAP(CMultiColorStatic)

ON_WM_PAINT() //爲這個類定義WM_PAINT消息處理函數

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

下面是這個類中的重要成員函數:

//爲CMultiColorStatic類添加「設置文本顔色」接口

void CMultiColorStatic::SetTextColor( COLORREF TextColor )

{

m_TextColor = TextColor; //設置文字顔色

}

//爲CMultiColorStatic類添加「設置背景顔色」接口

void CMultiColorStatic::SetBackColor( COLORREF BackColor )

{

m_BackColor = BackColor; //設置背景顔色

}

//爲CMultiColorStatic類添加「設置標題」接口

void CMultiColorStatic::SetCaption( CString strCaption )

{

m_strCaption = strCaption;

}

//重畫Static,顔色和標題的設置都依靠于這個函數

void CMultiColorStatic::OnPaint()

{

CPaintDC dc(this); // device context for painting

CRect rect;

GetClientRect( &rect );

dc.SetBkColor( m_BackColor );

dc.SetBkMode( TRANSPARENT );

CFont *pFont = GetParent()->GetFont();//得到父窗體的字體

CFont *pOldFont;

pOldFont = dc.SelectObject( pFont );//選用父窗體的字體

dc.SetTextColor( m_TextColor );//設置文本顔色

dc.DrawText( m_strCaption, &rect, DT_CENTER );//文本在Static中心

dc.SelectObject( pOldFont );

}

爲了驗證CMultiColorStatic類,我們制作一個基于對話框的應用程序,它包含一個如圖17所示的對話框。該對話框上包括一個static控件和三個按鈕,這三個按鈕可分別把static控件設置爲「紅色」、「藍色」和「綠色」。

VC++動態鏈接庫編程之MFC擴展 DLL

圖17 擴展的CStatic類調用演示

下面看看應如何編寫與這個對話框對應的類。

包含這種Static的對話框類的聲明如下:

#include "..\MultiColorStatic.h"

#pragma comment ( lib, "ColorStatic.lib" )

// CCallDllDlg dialog

class CCallDllDlg : public CDialog

{

public:

CCallDllDlg(CWnd* pParent = NULL); // standard constructor

enum { IDD = IDD_CALLDLL_DIALOG };

CMultiColorStatic m_colorstatic; //包含一個CMultiColorStatic的實例

protected:

virtual void DoDataExchange(CDataExchange* pDX);//DDX/DDV support

HICON m_hIcon;

// Generated message map functions

//{{AFX_MSG(CCallDllDlg)

virtual BOOL OnInitDialog();

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint();

afx_msg HCURSOR OnQueryDragIcon();

afx_msg void OnRedButton();

afx_msg void OnBlueButton();

afx_msg void OnGreenButton();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

下面是這個類中與使用CMultiColorStatic相關的主要成員函數:

void CCallDllDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CCallDllDlg)

DDX_Control(pDX, IDC_COLOR_STATIC, m_colorstatic);

//使m_colorstatic與IDC_COLOR_STATIC控件關聯

//}}AFX_DATA_MAP

}

BOOL CCallDllDlg::OnInitDialog()

{

// TODO: Add extra initialization here

// 初始static控件的顯示

m_colorstatic.SetCaption("最開始爲黑色");

m_colorstatic.SetTextColor(RGB(0,0,0));

return TRUE; // return TRUE unless you set the focus to a control

}

//設置static控件文本顔色爲紅色

void CCallDllDlg::OnRedButton()

{

m_colorstatic.SetCaption( "改變爲紅色" );

m_colorstatic.SetTextColor( RGB( 255, 0, 0 ) );

Invalidate( TRUE ); //導致發出WM_PAINT消息

}

//設置static控件文本顔色爲藍色

void CCallDllDlg::OnBlueButton()

{

m_colorstatic.SetCaption( "改變爲藍色" );

m_colorstatic.SetTextColor( RGB( 0, 0, 255 ) );

Invalidate( TRUE ); //導致發出WM_PAINT消息

}

//設置static控件文本顔色爲綠色

void CCallDllDlg::OnGreenButton()

{

m_colorstatic.SetCaption( "改變爲綠色" );

m_colorstatic.SetTextColor( RGB(0,255,0) );

Invalidate( TRUE ); //導致發出WM_PAINT消息

}

至此,我們已經講解完成了所有類型的動態鏈接庫,即非MFC DLL、MFC規則DLL和MFC擴展DLL。下一節將給出DLL的三個工程實例,與讀者朋友們共同體會DLL的應用範圍和使用方法。

 
特别声明:以上内容(如有图片或视频亦包括在内)为网络用户发布,本站仅提供信息存储服务。
 
DLL類型入口函數 非 MFC DLL 編程者提供DllMain函數 MFC規則 DLL CWinApp對象的InitInstance 和 ExitInstance MFC擴展 DLL MFC DLL向導生成DllMain 函數   對于MFC擴展DLL,系統會自動在工程中添加如下表所示的宏,這些宏爲DLL和應用程序的編寫提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA這樣的宏,在DLL和應用程序中將具有不同的定義,這取決于_AFXEXT宏是否被定義。這使得在DLL和應用程序中,使用統一的一個宏就可以表示出輸出和輸入的不同意思。在DLL中,表示輸出(因爲_AFXEXT被定義,通常是在編譯器的標識參數中指定/D_AFXEXT);在應用程序中,則表示輸入(_AFXEXT沒有定義)。 宏定義 AFX_CLASS_IMPORT __declspec(dlleXPort) AFX_API_IMPORT __declspec(dllexport) AFX_DATA_IMPORT __declspec(dllexport) AFX_CLASS_EXPORT __declspec(dllexport) AFX_API_EXPORT __declspec(dllexport) AFX_DATA_EXPORT __declspec(dllexport) AFX_EXT_CLASS #ifdef _AFXEXT  AFX_CLASS_EXPORT #else  AFX_CLASS_IMPORT AFX_EXT_API #ifdef _AFXEXT  AFX_API_EXPORT #else  AFX_API_IMPORT AFX_EXT_DATA #ifdef _AFXEXT  AFX_DATA_EXPORT #else  AFX_DATA_IMPORT   6.2 MFC擴展DLL導出MFC派生類   在這個例子中,我們將産生一個名爲「ExtDll」的MFC擴展DLL工程,在這個DLL中導出一個對話框類,這個對話框類派生自MFC類CDialog。   使用MFC向導生成MFC擴展DLL時,系統會自動添加如下代碼: static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL }; extern "C" int APIENTRY DllMain( HINSTANCE hInstance, DWord dwReason, LPVOID lPReserved ) {  // Remove this if you use lpReserved  UNREFERENCED_PARAMETER( lpReserved );  //說明:lpReserved是一個被系統所保留的參數,對于隱式鏈接是一個非零值,對于顯式鏈接值是零  if (dwReason == DLL_PROCESS_ATTACH)  {   TRACE0( "EXTDLL.DLL Initializing!\n" );   // Extension DLL one-time initialization   if ( !AfxInitExtensionModule( ExtDllDLL, hInstance ))    return 0;    // Insert this DLL into the resource chain   new CDynLinkLibrary( ExtDllDLL );  }  else if (dwReason == DLL_PROCESS_DETACH)  {   TRACE0( "EXTDLL.DLL Terminating!\n" );   // Terminate the library before destrUCtors are called   AfxTermExtensionModule( ExtDllDLL );  }  return 1; // ok }   這一段代碼含義晦澀,我們需要對其進行解讀:   (1)上述代碼完成MFC擴展DLL的初始化和終止處理;   (2)初始化期間所創建的 CDynLinkLibrary 對象使MFC擴展 DLL 可以將 DLL中的CRuntimeClass 對象或資源導出到應用程序;   (3)AfxInitExtensionModule函數捕捉模塊的CRuntimeClass 結構和在創建 CDynLinkLibrary 對象時使用的對象工廠(COleObjectFactory 對象);   (4)AfxTermExtensionModule函數使 MFC 得以在每個進程與擴展 DLL 分離時(進程退出或使用AfxFreeLibrary卸載DLL時)清除擴展 DLL;   (5)第一條語句static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };定義了一個AFX_EXTENSION_MODULE類的靜態全局對象,AFX_EXTENSION_MODULE的定義如下: struct AFX_EXTENSION_MODULE {  BOOL bInitialized;  HMODULE hModule;  HMODULE hResource;  CRuntimeClass* pFirstSharedClass;  COleObjectFactory* pFirstSharedFactory; };   由AFX_EXTENSION_MODULE的定義我們可以更好的理解(2)、(3)、(4)點。   在資源編輯器中添加一個如圖15所示的對話框,並使用MFC類向導爲其添加一個對應的類CExtDialog,系統自動添加了ExtDialog.h和ExtDialog.cpp兩個頭文件。 [url=/bbs/detail_1785391.html][img]http://image.wangchao.net.cn/it/1323423613050.jpg[/img][/url] 圖15 MFC擴展DLL中的對話框   修改ExtDialog.h中CExtDialog類的聲明爲: class AFX_EXT_CLASS CExtDialog : public CDialog {  public:   CExtDialog( CWnd* pParent = NULL );   enum { IDD = IDD_DLL_DIALOG };  protected:   virtual void DoDataExchange( CDataExchange* pDX );   DECLARE_MESSAGE_MAP() };   這其中最主要的改變是我們在class AFX_EXT_CLASS CExtDialog語句中添加了「AFX_EXT_CLASS」宏,則使得DLL中的CExtDialog類被導出。 6.3 MFC擴展DLL的加載   6.3.1 隱式加載   我們在6.2工程所在的工作區中添加一個LoadExtDllDlg工程,用于演示MFC擴展DLL的加載。在LoadExtDllDlg工程中添加一個如圖16所示的對話框,這個對話框上包括一個「調用DLL」按鈕。 [url=/bbs/detail_1785391.html][img]http://image.wangchao.net.cn/it/1323423613219.jpg[/img][/url] 圖16 MFC擴展DLL調用工程中的對話框   在與圖16對應對話框類實現文件的頭部添加: // LoadExtDllDlg.cpp : implementation file // #include "..\ExtDialog.h" #pragma comment( lib, "ExtDll.lib" ) 而「調用DLL」按鈕的單擊事件的消息處理函數爲: void CLoadExtDllDlg::OnDllcallButton() {  CExtDialog extDialog;  extDialog.DoModal(); }   當我們單擊「調用DLL」的時候,彈出了如圖15的對話框。   爲提供給用戶隱式加載(MFC擴展DLL一般使用隱式加載,具體原因見下節),MFC擴展DLL需要提供三個文件:   (1)描述DLL中擴展類的頭文件;   (2)與動態鏈接庫對應的.LIB文件;   (3)動態鏈接庫.DLL文件本身。   有了這三個文件,應用程序的開發者才可充分利用MFC擴展DLL。   6.3.2 顯示加載   顯示加載MFC擴展DLL應使用MFC全局函數AfxLoadLibrary而不是WIN32 API中的LoadLibrary。AfxLoadLibrary 最終也調用了 LoadLibrary這個API,但是在調用之前進行了線程同步的處理。   AfxLoadLibrary 的函數原型與 LoadLibrary完全相同,爲: HINSTANCE AFXAPI AfxLoadLibrary( LPCTSTR lpszModuleName );   與之相對應的是,MFC 應用程序應使用AfxFreeLibrary 而非FreeLibrary 卸載MFC擴展DLL。AfxFreeLibrary的函數原型也與 FreeLibrary完全相同,爲: BOOL AFXAPI AfxFreeLibrary( HINSTANCE hInstLib );   假如我們把上例中的「調用DLL」按鈕單擊事件的消息處理函數改爲: void CLoadExtDllDlg::OnDllcallButton() {  HINSTANCE hDll = AfxLoadLibrary( "ExtDll.dll" );  if(NULL == hDll)  {   AfxMessageBox( "MFC擴展DLL動態加載失敗" );   return;  }  CExtDialog extDialog;  extDialog.DoModal();  AfxFreeLibrary(hDll); }   則工程會出現link錯誤: LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall CExtDialog::~CExtDialog(void)" (__imp_??1CExtDialogUAE@XZ) LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall CExtDialog::CExtDialog(class CWnd *)" (__imp_??0CExtDialogQAE@PAVCWnd@Z)   提示CExtDialog的構造函數和析構函數均無法找到!是的,對于派生MFC類的MFC擴展DLL,當我們要在應用程序中使用DLL中定義的派生類時,我們不宜使用動態加載DLL的方法。   6.4 MFC擴展DLL加載MFC擴展DLL   我們可以在MFC擴展DLL中再次使用MFC擴展DLL,但是,由于在兩個DLL中對于AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA宏的定義都是輸出,這會導致調用的時候出現問題。   我們將會在調用MFC擴展DLL的DLL中看到link錯誤: error LNK2001: unresolved external symbol ….......   因此,在調用MFC擴展DLL的MFC擴展DLL中,在包含被調用DLL的頭文件之前,需要臨時重新定義AFX_EXT_CLASS的值。下面的例子顯示了如何實現: //臨時改變宏的含義「輸出」爲「輸入」 #undef AFX_EXT_CLASS #undef AFX_EXT_API #undef AFX_EXT_DATA #define AFX_EXT_CLASS AFX_CLASS_IMPORT #define AFX_EXT_API AFX_API_IMPORT #define AFX_EXT_DATA AFX_DATA_IMPORT //包含被調用MFC擴展DLL的頭文件 #include "CalledDLL.h" //恢複宏的含義爲輸出 #undef AFX_EXT_CLASS #undef AFX_EXT_API #undef AFX_EXT_DATA #define AFX_EXT_CLASS AFX_CLASS_EXPORT #define AFX_EXT_API AFX_API_EXPORT #define AFX_EXT_DATA AFX_DATA_EXPORT 6.5 MFC擴展DLL導出函數和變量   MFC擴展DLL導出函數和變量的方法也十分簡單,下面我們給出一個簡單的例子。   我們在MFC向導生成的MFC擴展DLL工程中添加gobal.h和global.cpp兩個文件: //global.h:MFC擴展DLL導出變量和函數的聲明 extern "C" {  int AFX_EXT_DATA total; //導出變量  int AFX_EXT_API add( int x, int y ); //導出函數 } //global.cpp:MFC擴展DLL導出變量和函數定義 #include "StdAfx.h" #include "global.h" extern "C" int total; int add(int x,int y) {  total = x + y;  return total; }   編寫一個簡單的控制台程序來調用這個MFC擴展DLL: #include #include 單擊此處下載本工程)。   我們知道static控件所對應的CStatic類不具備設置背景和文本顔色的接口,這使得我們不能在對話框或其它用戶界面上自由靈活地修改static控件的顔色風格,因此我們需要一個提供了SetBackColor和SetTextColor接口的CStatic派生類CMultiColorStatic。     這個類的聲明如下: class AFX_EXT_CLASS CMultiColorStatic : public CStatic {  // Construction  public:   CMultiColorStatic();   virtual ~CMultiColorStatic();   // Attributes  protected:   CString m_strCaption;   COLORREF m_BackColor;   COLORREF m_TextColor;   // Operations  public:   void SetTextColor( COLORREF TextColor );   void SetBackColor( COLORREF BackColor );   void SetCaption( CString strCaption );   // Generated message map functions  protected:   afx_msg void OnPaint();   DECLARE_MESSAGE_MAP() };   在這個類的實現文件中,我們需要爲它提供WM_PAINT消息的處理函數(這是因爲顔色的設置依靠于WM_PAINT消息): BEGIN_MESSAGE_MAP(CMultiColorStatic, CStatic) //{{AFX_MSG_MAP(CMultiColorStatic)  ON_WM_PAINT() //爲這個類定義WM_PAINT消息處理函數 //}}AFX_MSG_MAP END_MESSAGE_MAP()   下面是這個類中的重要成員函數: //爲CMultiColorStatic類添加「設置文本顔色」接口 void CMultiColorStatic::SetTextColor( COLORREF TextColor ) {  m_TextColor = TextColor; //設置文字顔色 } //爲CMultiColorStatic類添加「設置背景顔色」接口 void CMultiColorStatic::SetBackColor( COLORREF BackColor ) {  m_BackColor = BackColor; //設置背景顔色 } //爲CMultiColorStatic類添加「設置標題」接口 void CMultiColorStatic::SetCaption( CString strCaption ) {  m_strCaption = strCaption; } //重畫Static,顔色和標題的設置都依靠于這個函數 void CMultiColorStatic::OnPaint() {  CPaintDC dc(this); // device context for painting  CRect rect;  GetClientRect( &rect );  dc.SetBkColor( m_BackColor );  dc.SetBkMode( TRANSPARENT );  CFont *pFont = GetParent()->GetFont();//得到父窗體的字體  CFont *pOldFont;  pOldFont = dc.SelectObject( pFont );//選用父窗體的字體  dc.SetTextColor( m_TextColor );//設置文本顔色  dc.DrawText( m_strCaption, &rect, DT_CENTER );//文本在Static中心  dc.SelectObject( pOldFont ); }   爲了驗證CMultiColorStatic類,我們制作一個基于對話框的應用程序,它包含一個如圖17所示的對話框。該對話框上包括一個static控件和三個按鈕,這三個按鈕可分別把static控件設置爲「紅色」、「藍色」和「綠色」。 [url=/bbs/detail_1785391.html][img]http://image.wangchao.net.cn/it/1323423613334.jpg[/img][/url] 圖17 擴展的CStatic類調用演示   下面看看應如何編寫與這個對話框對應的類。   包含這種Static的對話框類的聲明如下: #include "..\MultiColorStatic.h" #pragma comment ( lib, "ColorStatic.lib" ) // CCallDllDlg dialog class CCallDllDlg : public CDialog {  public:   CCallDllDlg(CWnd* pParent = NULL); // standard constructor   enum { IDD = IDD_CALLDLL_DIALOG };   CMultiColorStatic m_colorstatic; //包含一個CMultiColorStatic的實例  protected:   virtual void DoDataExchange(CDataExchange* pDX);//DDX/DDV support   HICON m_hIcon;  // Generated message map functions  //{{AFX_MSG(CCallDllDlg)  virtual BOOL OnInitDialog();  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);  afx_msg void OnPaint();  afx_msg HCURSOR OnQueryDragIcon();  afx_msg void OnRedButton();  afx_msg void OnBlueButton();  afx_msg void OnGreenButton(); //}}AFX_MSG DECLARE_MESSAGE_MAP() };   下面是這個類中與使用CMultiColorStatic相關的主要成員函數: void CCallDllDlg::DoDataExchange(CDataExchange* pDX) {  CDialog::DoDataExchange(pDX);  //{{AFX_DATA_MAP(CCallDllDlg)   DDX_Control(pDX, IDC_COLOR_STATIC, m_colorstatic);  //使m_colorstatic與IDC_COLOR_STATIC控件關聯  //}}AFX_DATA_MAP } BOOL CCallDllDlg::OnInitDialog() {  …  // TODO: Add extra initialization here  // 初始static控件的顯示  m_colorstatic.SetCaption("最開始爲黑色");  m_colorstatic.SetTextColor(RGB(0,0,0));  return TRUE; // return TRUE unless you set the focus to a control } //設置static控件文本顔色爲紅色 void CCallDllDlg::OnRedButton() {  m_colorstatic.SetCaption( "改變爲紅色" );  m_colorstatic.SetTextColor( RGB( 255, 0, 0 ) );  Invalidate( TRUE ); //導致發出WM_PAINT消息 } //設置static控件文本顔色爲藍色 void CCallDllDlg::OnBlueButton() {  m_colorstatic.SetCaption( "改變爲藍色" );  m_colorstatic.SetTextColor( RGB( 0, 0, 255 ) );  Invalidate( TRUE ); //導致發出WM_PAINT消息 } //設置static控件文本顔色爲綠色 void CCallDllDlg::OnGreenButton() {  m_colorstatic.SetCaption( "改變爲綠色" );  m_colorstatic.SetTextColor( RGB(0,255,0) );  Invalidate( TRUE ); //導致發出WM_PAINT消息 }   至此,我們已經講解完成了所有類型的動態鏈接庫,即非MFC DLL、MFC規則DLL和MFC擴展DLL。下一節將給出DLL的三個工程實例,與讀者朋友們共同體會DLL的應用範圍和使用方法。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有