zoukankan      html  css  js  c++  java
  • (转载)DLL动态链接库编程入门之五:MFC扩展DLL

     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:

    C++代码
    1. extern "C" int APIENTRY   
    2. DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)   
    3. {   
    4.    // Remove this if you use lpReserved   
    5.    UNREFERENCED_PARAMETER(lpReserved);   
    6.   
    7.    if (dwReason == DLL_PROCESS_ATTACH)   
    8.    {   
    9.       TRACE0("MFCEXPENDDLL.DLL Initializing! ");   
    10.   
    11.       // Extension DLL one-time initialization   
    12.       if (!AfxInitExtensionModule(MfcexpenddllDLL, hInstance))   
    13.         return 0;   
    14.   
    15.       // Insert this DLL into the resource chain   
    16.       // NOTE: If this Extension DLL is being implicitly linked to by   
    17.       //  an MFC Regular DLL (such as an ActiveX Control)   
    18.       //  instead of an MFC application, then you will want to   
    19.       //  remove this line from DllMain and put it in a separate   
    20.       //  function exported from this Extension DLL.  The Regular DLL   
    21.       //  that uses this Extension DLL should then explicitly call that   
    22.       //  function to initialize this Extension DLL.  Otherwise,   
    23.       //  the CDynLinkLibrary object will not be attached to the   
    24.       //  Regular DLL's resource chain, and serious problems will   
    25.       //  result.   
    26.   
    27.       new CDynLinkLibrary(MfcexpenddllDLL);   
    28.    }   
    29.    else if (dwReason == DLL_PROCESS_DETACH)   
    30.    {   
    31.       TRACE0("MFCEXPENDDLL.DLL Terminating! ");   
    32.       // Terminate the library before destructors are called   
    33.       AfxTermExtensionModule(MfcexpenddllDLL);   
    34.    }   
    35.    return 1;   // ok   
    36. }  

           上述代码完成MFC扩展DLL的初始化和终止处理。

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

           1、MFC扩展DLL的创建

      下面我们将在MFC扩展DLL中导出一个按钮类CSXButton(扩展自MFC的CButton类),类CSXButton是一个用以取代 CButton的类,它使你能在同一个按钮上显示位图和文字,而MFC的按钮仅可显示二者之一。类CSXbutton的源代码在Internet上广泛流传,有很好的“群众基础”,因此用这个类来讲解MFC扩展DLL有其特殊的功效。

      MFC中包含一些,这些宏在DLL和调用DLL的应用程序中被以不同的方式展开,这使得在DLL和应用程序中,使用统一的一个宏就可以表示出输出和输入的不同意思:

    C++代码
    1. // for data   
    2. #ifndef AFX_DATA_EXPORT   
    3.  #define AFX_DATA_EXPORT __declspec(dllexport)   
    4. #endif   
    5. #ifndef AFX_DATA_IMPORT   
    6.  #define AFX_DATA_IMPORT __declspec(dllimport)   
    7. #endif   
    8.   
    9. // for classes   
    10. #ifndef AFX_CLASS_EXPORT   
    11.  #define AFX_CLASS_EXPORT __declspec(dllexport)   
    12. #endif   
    13. #ifndef AFX_CLASS_IMPORT   
    14.  #define AFX_CLASS_IMPORT __declspec(dllimport)   
    15. #endif   
    16.   
    17. // for global APIs   
    18. #ifndef AFX_API_EXPORT   
    19.  #define AFX_API_EXPORT __declspec(dllexport)   
    20. #endif   
    21. #ifndef AFX_API_IMPORT   
    22.  #define AFX_API_IMPORT __declspec(dllimport)   
    23. #endif   
    24.   
    25. #ifndef AFX_EXT_DATA   
    26.  #ifdef _AFXEXT   
    27.   #define AFX_EXT_CLASS       AFX_CLASS_EXPORT   
    28.   #define AFX_EXT_API         AFX_API_EXPORT   
    29.   #define AFX_EXT_DATA        AFX_DATA_EXPORT   
    30.   #define AFX_EXT_DATADEF   
    31.  #else   
    32.   #define AFX_EXT_CLASS       AFX_CLASS_IMPORT   
    33.   #define AFX_EXT_API         AFX_API_IMPORT   
    34.   #define AFX_EXT_DATA        AFX_DATA_IMPORT   
    35.   #define AFX_EXT_DATADEF   
    36.  #endif   
    37. #endif  

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

    C++代码
    1. #ifndef _SXBUTTON_H   
    2. #define _SXBUTTON_H   
    3.   
    4. #define SXBUTTON_CENTER -1   
    5.   
    6. class AFX_EXT_CLASS CSXButton : public CButton   
    7. {   
    8. // Construction   
    9. public:   
    10.  CSXButton();   
    11.   
    12. // Attributes   
    13. private:   
    14.  // Positioning   
    15.  BOOL  m_bUseOffset;       
    16.  CPoint  m_pointImage;   
    17.  CPoint  m_pointText;   
    18.  int   m_nImageOffsetFromBorder;   
    19.  int   m_nTextOffsetFromImage;   
    20.   
    21.  // Image   
    22.  HICON  m_hIcon;        
    23.  HBITMAP  m_hBitmap;   
    24.  HBITMAP  m_hBitmapDisabled;   
    25.  int   m_nImageWidth, m_nImageHeight;   
    26.   
    27.  // Color Tab   
    28.  char  m_bColorTab;       
    29.  COLORREF m_crColorTab;   
    30.   
    31.  // State   
    32.  BOOL  m_bDefault;   
    33.  UINT  m_nOldAction;   
    34.  UINT  m_nOldState;   
    35.     
    36. // Operations   
    37. public:   
    38.  // Positioning   
    39.  int  SetImageOffset( int nPixels );    
    40.  int  SetTextOffset( int nPixels );   
    41.  CPoint SetImagePos( CPoint p );   
    42.  CPoint SetTextPos( CPoint p );   
    43.   
    44.  // Image   
    45.  BOOL SetIcon( UINT nID, int nWidth, int nHeight );   
    46.  BOOL SetBitmap( UINT nID, int nWidth, int nHeight );   
    47.  BOOL SetMaskedBitmap( UINT nID, int nWidth, int nHeight, COLORREF crTransparentMask );   
    48.  BOOL HasImage() { return (BOOL)( m_hIcon != 0  | m_hBitmap != 0 ); }   
    49.   
    50.  // Color Tab   
    51.  void SetColorTab(COLORREF crTab);   
    52.   
    53.  // State   
    54.  BOOL SetDefaultButton( BOOL bState = TRUE );   
    55. private:   
    56.  BOOL SetBitmapCommon( UINT nID, int nWidth, int nHeight, COLORREF crTransparentMask, BOOL bUseMask );   
    57.  void CheckPointForCentering( CPoint &p, int nWidth, int nHeight );   
    58.  void Redraw();   
    59.   
    60. // Overrides   
    61.  // ClassWizard generated virtual function overrides   
    62.  //{{AFX_VIRTUAL(CSXButton)   
    63.  public:   
    64.  virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);   
    65.  //}}AFX_VIRTUAL   
    66.   
    67. // Implementation   
    68. public:   
    69.  virtual ~CSXButton();   
    70.   
    71.  // Generated message map functions   
    72. protected:   
    73.  //{{AFX_MSG(CSXButton)   
    74.  afx_msg LRESULT OnGetText(WPARAM wParam, LPARAM lParam);   
    75.  //}}AFX_MSG   
    76.   
    77.  DECLARE_MESSAGE_MAP()   
    78. };   
    79.   
    80. #endif  

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

    DLL导出类时导出的大量符号

    图1 导出类时导出的大量符号

      这些都是类的构造函数、析构函数及其它成员函数和变量经编译器处理过的符号,我们直接用__declspec(dllexport)语句声明类就导出了这些符号。

      如果我们想用.lib文件导出这些符号,是非常困难的,我们需要在工程中生成.map文件,查询.map文件的符号,然后将其一一导出。如图2,打开DLL工程的settings选项,再选择Link,勾选其中的产生MAP文件(Generate mapfile)就可以产生.map文件了。

      打开mfcexpenddll工程生成的.map文件,我们发现其中包含了图1中所示的符号(symbol)。

    C++代码
    1. 0001:00000380  ?HasImage@CSXButton@@QAEHXZ 10001380 f i SXBUTTON.OBJ   
    2. 0001:000003d0  ??0CSXButton@@QAE@XZ       100013d0 f   SXBUTTON.OBJ   
    3. 0001:00000500  ??_GCSXButton@@UAEPAXI@Z   10001500 f i SXBUTTON.OBJ   
    4. 0001:00000570  ??_ECSXButton@@UAEPAXI@Z   10001570 f i SXBUTTON.OBJ   
    5. 0001:00000630  ??1CSXButton@@UAE@XZ       10001630 f   SXBUTTON.OBJ   
    6. 0001:00000700 ?_GetBaseMessageMap@CSXButton@@KGPBUAFX_MSGMAP@@XZ 10001700 f   SXBUTTON.OBJ   
    7. 0001:00000730 ?GetMessageMap@CSXButton@@MBEPBUAFX_MSGMAP@@XZ 10001730 f   SXBUTTON.OBJ   
    8. 0001:00000770    ?Redraw@CSXButton@@AAEXXZ  10001770 f i SXBUTTON.OBJ   
    9. 0001:000007d0    ?SetIcon@CSXButton@@QAEHIHH@Z 100017d0 f   SXBUTTON.OBJ   
    10. ……………………………………………………………………..//省略  

    产生.map文件

    图2 产生.map文件

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

           2、MFC扩展DLL的调用

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

    设置按钮属性为“Owner draw”

    图3 设置按钮属性为“Owner draw”

           在工程中添加两个ICON资源:IDI_MSN_ICON(MSN的图标)、IDI_REFBAR_ICON(Windows的系统图标)。

      修改工程的“calldllDlg.h”头文件为:

    C++代码
    1. #include "....mfcexpenddllSXBUTTON.h"  //包含dll的导出类头文件   
    2. #pragma comment(lib,"mfcexpenddll.lib")    //隐式链接dll   
    3. /////////////////////////////////////////////////////////////////////////////  
    4. // CCalldllDlg dialog   
    5.   
    6. class CCalldllDlg : public CDialog   
    7. {   
    8. // Construction   
    9. public:   
    10.  CCalldllDlg(CWnd* pParent = NULL); // standard constructor   
    11.   
    12. // Dialog Data   
    13.  //{{AFX_DATA(CCalldllDlg)   
    14.  enum { IDD = IDD_CALLDLL_DIALOG };   
    15. //增加与两个按钮对应的成员变量   
    16.  CSXButton m_button1;      
    17.  CSXButton m_button2;   
    18. …   
    19. }  

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

    C++代码
    1. void CCalldllDlg::DoDataExchange(CDataExchange* pDX)   
    2. {   
    3.  CDialog::DoDataExchange(pDX);   
    4.  //{{AFX_DATA_MAP(CCalldllDlg)   
    5.  DDX_Control(pDX, IDC_BUTTON2, m_button2);   
    6.  DDX_Control(pDX, IDC_BUTTON1, m_button1);   
    7.  //}}AFX_DATA_MAP   
    8. }  

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

    C++代码
    1. BOOL CCalldllDlg::OnInitDialog()   
    2. {   
    3.  CDialog::OnInitDialog();   
    4.   
    5.  // Add "About..." menu item to system menu.   
    6.   
    7.  // IDM_ABOUTBOX must be in the system command range.   
    8.  ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);   
    9.  ASSERT(IDM_ABOUTBOX < 0xF000);   
    10.   
    11.  CMenu* pSysMenu = GetSystemMenu(FALSE);   
    12.  if (pSysMenu != NULL)   
    13.  {   
    14.   CString strAboutMenu;   
    15.   strAboutMenu.LoadString(IDS_ABOUTBOX);   
    16.   if (!strAboutMenu.IsEmpty())   
    17.   {   
    18.    pSysMenu->AppendMenu(MF_SEPARATOR);   
    19.    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);   
    20.   }   
    21.  }   
    22.   
    23.  // Set the icon for this dialog.  The framework does this automatically   
    24.  //  when the application's main window is not a dialog   
    25.  SetIcon(m_hIcon, TRUE);   // Set big icon   
    26.  SetIcon(m_hIcon, FALSE);  // Set small icon   
    27.   
    28.  // TODO: Add extra initialization here   
    29.  m_button1.SetIcon(IDI_MSN_ICON,16,16);   
    30.  m_button2.SetIcon(IDI_REFBAR_ICON,16,16);   
    31.   
    32.  return TRUE;  // return TRUE  unless you set the focus to a control  
    33. }  

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

    DLL扩展的按钮被显示

    图4 DLL扩展的按钮被显示

      如果我们不修改void CCalldllDlg::DoDataExchange(CDataExchange* pDX),即不增加下列代码:

    C++代码
    1. DDX_Control(pDX, IDC_BUTTON2,  m_button2);   
    2. DDX_Control(pDX, IDC_BUTTON1,  m_button1);  

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

    C++代码
    1. m_button1.SubclassDlgItem(IDC_BUTTON1, this);   
    2. m_button2.SubclassDlgItem(IDC_BUTTON2, this);  

      但是,DDX_Control与按钮类的SubclassDlgItem成员函数不能同时存在,否则程序会出错。

           3、总结

      由以上分析可知,MFC扩展DLL的导出与引用方式与前几节所讲述的方式没有太大的差别,MFC扩展DLL主要强调对MFC进行功能扩展。因此,如果DLL的目标不是增强MFC的功能,其与应用程序的接口也不是MFC,请不要将DLL建立为MFC扩展DLL。

    原文地址:http://www.jizhuomi.com/software/301.html

  • 相关阅读:
    Google快照查看八大绝招[小摘]
    CSS li或dd 浮动后增加图片时多出4PX问题
    ASP.NET C# 邮件发送全解
    ff ie7 ie6 css支持问题[拼网页标记]
    net 中 等同与ajax的效果 ICallbackEventHandler
    让DIV层位于flash对象之上
    屏蔽JS错误代码
    META标签的使用摘录,网页跳转特效
    【转】海量数据处理常用思路和方法
    MFC画图定时刷新,能否做到完全无闪烁
  • 原文地址:https://www.cnblogs.com/wodehao0808/p/6759095.html
Copyright © 2011-2022 走看看