您的位置:首页 > 编程语言

(转载)DLL动态链接库编程入门之五:MFC扩展DLL

2017-04-24 21:07 393 查看
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++代码

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的创建及在应用程序中调用它的例子。

1、MFC扩展DLL的创建

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

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

C++代码

// 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类的例子:

C++代码

#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,发现其导出了众多符号(见图1)。



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

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

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

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

C++代码

0001:00000380 ?HasImage@CSXButton@@QAEHXZ 10001380 f i SXBUTTON.OBJ

0001:000003d0 ??0CSXButton@@QAE@XZ 100013d0 f SXBUTTON.OBJ

0001:00000500 ??_GCSXButton@@UAEPAXI@Z 10001500 f i SXBUTTON.OBJ

0001:00000570 ??_ECSXButton@@UAEPAXI@Z 10001570 f i SXBUTTON.OBJ

0001:00000630 ??1CSXButton@@UAE@XZ 10001630 f SXBUTTON.OBJ

0001:00000700 ?_GetBaseMessageMap@CSXButton@@KGPBUAFX_MSGMAP@@XZ 10001700 f SXBUTTON.OBJ

0001:00000730 ?GetMessageMap@CSXButton@@MBEPBUAFX_MSGMAP@@XZ 10001730 f SXBUTTON.OBJ

0001:00000770 ?Redraw@CSXButton@@AAEXXZ 10001770 f i SXBUTTON.OBJ

0001:000007d0 ?SetIcon@CSXButton@@QAEHIHH@Z 100017d0 f SXBUTTON.OBJ

……………………………………………………………………..//省略



图2 产生.map文件

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

2、MFC扩展DLL的调用

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



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

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

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

C++代码

#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成员变量与对话框上的按钮控件建立关联:

C++代码

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的代码:

C++代码

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

}

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



图4 DLL扩展的按钮被显示

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

C++代码

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的关联:

C++代码

m_button1.SubclassDlgItem(IDC_BUTTON1, this);

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: