MFC扩展DLL的内涵为MFC的扩展,用户使用MFC扩展DLL就像使用MFC本身的DLL一样。除了可以在MFC扩展DLL的内部使用MFC以外,MFC扩展DLL与应用程序的接口部分也可以是MFC。我们一般使用MFC扩展DLL来包含一些MFC的增强功能,譬如扩展MFC的CStatic、CButton等类使之具备更强大的能力。使用Visual C++向导生产MFC扩展DLL时,MFC向导会自动增加DLL的入口函数DllMain:

extern "C" int APIENTRY 
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 
{ 
 // Remove this if you use lpReserved 
 UNREFERENCED_PARAMETER(lpReserved); 
 
 if (dwReason == DLL_PROCESS_ATTACH) 
 { 
  TRACE0("MFCEXPENDDLL.DLL Initializing!\n"); 
 
  // Extension DLL one-time initialization 
  if (!AfxInitExtensionModule(MfcexpenddllDLL, hInstance)) 
   return 0; 
 
  // Insert this DLL into the resource chain 
  // NOTE: If this Extension DLL is being implicitly linked to by 
  //  an MFC Regular DLL (such as an ActiveX Control) 
  //  instead of an MFC application, then you will want to 
  //  remove this line from DllMain and put it in a separate 
  //  function exported from this Extension DLL.  The Regular DLL 
  //  that uses this Extension DLL should then explicitly call that 
  //  function to initialize this Extension DLL.  Otherwise, 
  //  the CDynLinkLibrary object will not be attached to the 
  //  Regular DLL's resource chain, and serious problems will 
  //  result. 
 
  new CDynLinkLibrary(MfcexpenddllDLL); 
 } 
 else if (dwReason == DLL_PROCESS_DETACH) 
 { 
  TRACE0("MFCEXPENDDLL.DLL Terminating!\n"); 
  // Terminate the library before destructors are called
AfxTermExtensionModule(MfcexpenddllDLL); 
 } 
 return 1;   // ok 
}

上述代码完成MFC扩展DLL的初始化和终止处理。由于MFC扩展DLL导出函数和变量的方式与其它DLL没有什么区别,我们不再细致讲解。下面直接给出一个MFC扩展DLL的创建及在应用程序中调用它的例子。

    

创建MFC扩展DLL:

下面我们将在MFC扩展DLL中导出一个按钮类CSXButton(扩展自MFC的CButton类),类CSXButton是一个用以取代CButton的类,它使你能在同一个按钮上显示位图和文字,而MFC的按钮仅可显示二者之一。类CSXbutton的源代码在Internet上广泛流传,有很好的“群众基础”,因此用这个类来讲解MFC扩展DLL有其特殊的功效。   MFC中包含一些宏,这些宏在DLL和调用DLL的应用程序中被以不同的方式展开,这使得在DLL和应用程序中,使用统一的一个宏就可以表示出输出和输入的不同意思:

// for data 
#ifndef AFX_DATA_EXPORT 
 #define AFX_DATA_EXPORT __declspec(dllexport) 
#endif 
#ifndef AFX_DATA_IMPORT 
 #define AFX_DATA_IMPORT __declspec(dllimport) 
#endif 
 
// for classes 
#ifndef AFX_CLASS_EXPORT 
 #define AFX_CLASS_EXPORT __declspec(dllexport) 
#endif 
#ifndef AFX_CLASS_IMPORT 
 #define AFX_CLASS_IMPORT __declspec(dllimport) 
#endif 
 
// for global APIs 
#ifndef AFX_API_EXPORT 
 #define AFX_API_EXPORT __declspec(dllexport) 
 #endif 
#ifndef AFX_API_IMPORT 
 #define AFX_API_IMPORT __declspec(dllimport) 
#endif 
 
#ifndef AFX_EXT_DATA 
 #ifdef _AFXEXT 
  #define AFX_EXT_CLASS       AFX_CLASS_EXPORT 
  #define AFX_EXT_API         AFX_API_EXPORT 
  #define AFX_EXT_DATA        AFX_DATA_EXPORT 
  #define AFX_EXT_DATADEF 
 #else 
  #define AFX_EXT_CLASS       AFX_CLASS_IMPORT 
  #define AFX_EXT_API         AFX_API_IMPORT 
  #define AFX_EXT_DATA        AFX_DATA_IMPORT 
  #define AFX_EXT_DATADEF 
 #endif 
#endif

导出一个类,直接在类声明头文件中使用AFX_EXT_CLASS即可,以下是导出CSXButton类的例子:

#ifndef _SXBUTTON_H 
#define _SXBUTTON_H 
 
#define SXBUTTON_CENTER -1 
 
class AFX_EXT_CLASS CSXButton : public CButton 
{ 
// Construction 
public: 
 CSXButton(); 
 
// Attributes 
private: 
 // Positioning 
 BOOL  m_bUseOffset;     
 CPoint  m_pointImage; 
 CPoint  m_pointText; 
 int   m_nImageOffsetFromBorder; 
 int   m_nTextOffsetFromImage; 
 
 // Image
  HICON  m_hIcon;      
 HBITMAP  m_hBitmap; 
 HBITMAP  m_hBitmapDisabled; 
 int   m_nImageWidth, m_nImageHeight; 
 
 // Color Tab 
 char  m_bColorTab;     
 COLORREF m_crColorTab; 
 
 // State 
 BOOL  m_bDefault; 
 UINT  m_nOldAction; 
 UINT  m_nOldState; 
  
// Operations 
public: 
 // Positioning 
 int  SetImageOffset( int nPixels );  
 int  SetTextOffset( int nPixels ); 
 CPoint SetImagePos( CPoint p ); 
 CPoint SetTextPos( CPoint p ); 
 
 // Image 
 BOOL SetIcon( UINT nID, int nWidth, int nHeight ); 
 BOOL SetBitmap( UINT nID, int nWidth, int nHeight ); 
 BOOL SetMaskedBitmap( UINT nID, int nWidth, int nHeight, COLORREF 
crTransparentMask ); 
 BOOL HasImage() { return (BOOL)( m_hIcon != 0  | m_hBitmap != 0 ); } 
 
 // Color Tab 
 void SetColorTab(COLORREF crTab); 
 
 // State 
 BOOL SetDefaultButton( BOOL bState = TRUE ); 
private: 
 BOOL SetBitmapCommon( UINT nID, int nWidth, int nHeight, COLORREF 
crTransparentMask, BOOL bUseMask ); 
 void CheckPointForCentering( CPoint &p, int nWidth, int nHeight ); 
 void Redraw(); 
 
// Overrides 
 // ClassWizard generated virtual function overrides 
 //{{AFX_VIRTUAL(CSXButton) 
 public: 
  virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); 
 //}}AFX_VIRTUAL 
 
// Implementation 
public: 
 virtual ~CSXButton(); 
 
 // Generated message map functions 
protected: 
 //{{AFX_MSG(CSXButton) 
 afx_msg LRESULT OnGetText(WPARAM wParam, LPARAM lParam); 
 //}}AFX_MSG 
 
 DECLARE_MESSAGE_MAP() 
}; 
 
#endif


把SXBUTTON.CPP文件直接添加到工程,编译工程,得“mfcexpenddll.lib”和“mfcexpenddll.dll”两个文件。我们用Visual Studio自带的Depends工具可以查看这个.dll,发现其导出了众多符号(见图)。

                 VC++动态链接库(DLL)编程深入浅出(四) 出处:PConline_第1张图片

这些都是类的构造函数、析构函数及其它成员函数和变量经编译器处理过的符号,我们直接用__declspec(dllexport)语句声明类就导出了这些符号。 如果我们想用.lib文件导出这些符号,是非常困难的,我们需要在工程中生成.map文件,查询.map文件的符号,然后将其一一导出。如图,打开DLL工程的settings选项,再选择Link,勾选其中的产生MAP文件(Generate mapfile)就可以产生.map文件了。打开mfcexpenddll工程生成的.map文件,我们发现其中包含了图中所示的符号(symbol)

           VC++动态链接库(DLL)编程深入浅出(四) 出处:PConline_第2张图片

                  VC++动态链接库(DLL)编程深入浅出(四) 出处:PConline_第3张图片 

所以,对于MFC扩展DLL,我们不宜以.lib文件导出类。


调用MFC扩展DLL:

在DLL所在工作区新增一个dllcall工程,它是一个基于对话框的MFCEXE程序。在其中增加两个按钮SXBUTTON1、SXBUTTON2,并设置其属性为“Owner draw”,如图。

               VC++动态链接库(DLL)编程深入浅出(四) 出处:PConline_第4张图片

在工程中添加两个ICON资源:IDI_MSN_ICON(MSN的图标)、IDI_REFBAR_ICON(Windows的系统图标)。修改工程的“calldllDlg.h”头文件为:

#include "..\..\mfcexpenddll\SXBUTTON.h"  //

包含dll的导出类头文件

#pragma comment(lib,"mfcexpenddll.lib")    //

隐式链接dll 

///////////////////////////////////////////////////////////////////////////// 

// CCalldllDlg dialog 

class CCalldllDlg : public CDialog 
{ 
// Construction 
public: 
 CCalldllDlg(CWnd* pParent = NULL); // standard constructor 
 
// Dialog Data 
 //{{AFX_DATA(CCalldllDlg) 
 enum { IDD = IDD_CALLDLL_DIALOG };

//

增加与两个按钮对应的成员变量

CSXButton m_button1;    
 CSXButton m_button2;

  

同时,修改“calldllDlg.cpp”文件,使得m_button1,m_button2成员变量与对话框上的按钮控件建立关联:

void CCalldllDlg::DoDataExchange(CDataExchange* pDX) 
{ 
 CDialog::DoDataExchange(pDX); 
 //{{AFX_DATA_MAP(CCalldllDlg) 
 DDX_Control(pDX, IDC_BUTTON2, m_button2); 
 DDX_Control(pDX, IDC_BUTTON1, m_button1); 
 //}}AFX_DATA_MAP 
}

修改BOOL CCalldllDlg::OnInitDialog()函数,在其中增加对两个按钮设置ICON的代码: 

 BOOL CCalldllDlg::OnInitDialog() 
{ 
 CDialog::OnInitDialog(); 
 
 // Add "About..." menu item to system menu. 
 
 // IDM_ABOUTBOX must be in the system command range. 
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
 ASSERT(IDM_ABOUTBOX < 0xF000); 
 
 CMenu* pSysMenu = GetSystemMenu(FALSE); 
 if (pSysMenu != NULL) 
 { 
  CString strAboutMenu; 
  strAboutMenu.LoadString(IDS_ABOUTBOX); 
  if (!strAboutMenu.IsEmpty()) 
  { 
   pSysMenu->AppendMenu(MF_SEPARATOR); 
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
  } 
 } 
 
 // Set the icon for this dialog.  The framework does this automatically 
 //  when the application's main window is not a dialog 
 SetIcon(m_hIcon, TRUE);   // Set big icon 
 SetIcon(m_hIcon, FALSE);  // Set small icon
  // TODO: Add extra initialization here 
 m_button1.SetIcon(IDI_MSN_ICON,16,16); 
 m_button2.SetIcon(IDI_REFBAR_ICON,16,16); 
 
 return TRUE;  // return TRUE  unless you set the focus to a control 
}

 

 运行程序,将出现如图的对话框,图形和文字同时出现在按钮上,这说明我们正确地调用了

MFC扩展DLL。

                   

如果我们不修改void CCalldllDlg::DoDataExchange(CDataExchange* pDX)

,即不增加下列代码:

DDX_Control(pDX, IDC_BUTTON2,  m_button2); 

DDX_Control(pDX, IDC_BUTTON1,  m_button1); 

  

我们也可以在BOOL CCalldllDlg::OnInitDialog()函数中添加如下代码实现m_button1、m_button2与IDC_BUTTON1、IDC_BUTTON2的关联:

m_button1.SubclassDlgItem(IDC_BUTTON1, this); 

m_button2.SubclassDlgItem(IDC_BUTTON2, this); 

  

总结:

但是,DDX_Control与按钮类的SubclassDlgItem成员函数不能同时存在,否则程序会出错。由以上分析可知,MFC扩展DLL的导出与引用方式与前几节所讲述的方式没有太大的差别,MFC扩展DLL主要强调对MFC进行功能扩展。因此,如果DLL的目标不是增强MFC的功能,其与应用程序的接口也不是MFC,请不要将DLL建立为MFC扩展DLL。




本文来自:http://www.doc88.com/p-096200652967.html