VC++动态链接库编程之MFC扩展 DLL.docx

上传人:b****6 文档编号:8503085 上传时间:2023-01-31 格式:DOCX 页数:11 大小:20.06KB
下载 相关 举报
VC++动态链接库编程之MFC扩展 DLL.docx_第1页
第1页 / 共11页
VC++动态链接库编程之MFC扩展 DLL.docx_第2页
第2页 / 共11页
VC++动态链接库编程之MFC扩展 DLL.docx_第3页
第3页 / 共11页
VC++动态链接库编程之MFC扩展 DLL.docx_第4页
第4页 / 共11页
VC++动态链接库编程之MFC扩展 DLL.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

VC++动态链接库编程之MFC扩展 DLL.docx

《VC++动态链接库编程之MFC扩展 DLL.docx》由会员分享,可在线阅读,更多相关《VC++动态链接库编程之MFC扩展 DLL.docx(11页珍藏版)》请在冰豆网上搜索。

VC++动态链接库编程之MFC扩展 DLL.docx

VC++动态链接库编程之MFC扩展DLL

VC++动态链接库编程之MFC扩展DLL

资料引用:

DLL类型入口函数非MFCDLL编程者提供DllMain函数MFC规则DLLCWinApp对象的InitInstance和ExitInstanceMFC扩展DLLMFCDLL向导生成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_IMPORTAFX_EXT_API#ifdef_AFXEXT

 AFX_API_EXPORT

#else

 AFX_API_IMPORTAFX_EXT_DATA#ifdef_AFXEXT

 AFX_DATA_EXPORT

#else

 AFX_DATA_IMPORT

  6.2MFC扩展DLL导出MFC派生类

  在这个例子中,我们将产生一个名为“ExtDll”的MFC扩展DLL工程,在这个DLL中导出一个对话框类,这个对话框类派生自MFC类CDialog。

  使用MFC向导生成MFC扩展DLL时,系统会自动添加如下代码:

staticAFX_EXTENSION_MODULEExtDllDLL={NULL,NULL};

extern"C"intAPIENTRY

DllMain(HINSTANCEhInstance,DWorddwReason,LPVOIDlPReserved)

{

 //RemovethisifyouuselpReserved

 UNREFERENCED_PARAMETER(lpReserved);

 //说明:

lpReserved是一个被系统所保留的参数,对于隐式链接是一个非零值,对于显式链接值是零

 if(dwReason==DLL_PROCESS_ATTACH)

 {

  TRACE0("EXTDLL.DLLInitializing!

\n");

  //ExtensionDLLone-timeinitialization

  if(!

AfxInitExtensionModule(ExtDllDLL,hInstance))

   return0;

   //InsertthisDLLintotheresourcechain

  newCDynLinkLibrary(ExtDllDLL);

 }

 elseif(dwReason==DLL_PROCESS_DETACH)

 {

  TRACE0("EXTDLL.DLLTerminating!

\n");

  //TerminatethelibrarybeforedestrUCtorsarecalled

  AfxTermExtensionModule(ExtDllDLL);

 }

 return1;//ok

}

  这一段代码含义晦涩,我们需要对其进行解读:

  

(1)上述代码完成MFC扩展DLL的初始化和终止处理;

  

(2)初始化期间所创建的CDynLinkLibrary对象使MFC扩展DLL可以将DLL中的CRuntimeClass对象或资源导出到应用程序;

  (3)AfxInitExtensionModule函数捕捉模块的CRuntimeClass结构和在创建CDynLinkLibrary对象时使用的对象工厂(COleObjectFactory对象);

  (4)AfxTermExtensionModule函数使MFC得以在每个进程与扩展DLL分离时(进程退出或使用AfxFreeLibrary卸载DLL时)清除扩展DLL;

  (5)第一条语句staticAFX_EXTENSION_MODULEExtDllDLL={NULL,NULL};定义了一个AFX_EXTENSION_MODULE类的静态全局对象,AFX_EXTENSION_MODULE的定义如下:

structAFX_EXTENSION_MODULE

{

 BOOLbInitialized;

 HMODULEhModule;

 HMODULEhResource;

 CRuntimeClass*pFirstSharedClass;

 COleObjectFactory*pFirstSharedFactory;

};

  由AFX_EXTENSION_MODULE的定义我们可以更好的理解

(2)、(3)、(4)点。

  在资源编辑器中添加一个如图15所示的对话框,并使用MFC类向导为其添加一个对应的类CExtDialog,系统自动添加了ExtDialog.h和ExtDialog.cpp两个头文件。

图15MFC扩展DLL中的对话框

  修改ExtDialog.h中CExtDialog类的声明为:

classAFX_EXT_CLASSCExtDialog:

publicCDialog

{

 public:

  CExtDialog(CWnd*pParent=NULL);

  enum{IDD=IDD_DLL_DIALOG};

 protected:

  virtualvoidDoDataExchange(CDataExchange*pDX);

  DECLARE_MESSAGE_MAP()

};

  这其中最主要的改变是我们在classAFX_EXT_CLASSCExtDialog语句中添加了“AFX_EXT_CLASS”宏,则使得DLL中的CExtDialog类被导出。

6.3MFC扩展DLL的加载

  6.3.1隐式加载

  我们在6.2工程所在的工作区中添加一个LoadExtDllDlg工程,用于演示MFC扩展DLL的加载。

在LoadExtDllDlg工程中添加一个如图16所示的对话框,这个对话框上包括一个“调用DLL”按钮。

图16MFC扩展DLL调用工程中的对话框

  在与图16对应对话框类实现文件的头部添加:

//LoadExtDllDlg.cpp:

implementationfile

//

#include"..\ExtDialog.h"

#pragmacomment(lib,"ExtDll.lib")

而“调用DLL”按钮的单击事件的消息处理函数为:

voidCLoadExtDllDlg:

:

OnDllcallButton()

{

 CExtDialogextDialog;

 extDialog.DoModal();

}

  当我们单击“调用DLL”的时候,弹出了如图15的对话框。

  为提供给用户隐式加载(MFC扩展DLL一般使用隐式加载,具体原因见下节),MFC扩展DLL需要提供三个文件:

  

(1)描述DLL中扩展类的头文件;

  

(2)与动态链接库对应的.LIB文件;

  (3)动态链接库.DLL文件本身。

  有了这三个文件,应用程序的开发者才可充分利用MFC扩展DLL。

  6.3.2显示加载

  显示加载MFC扩展DLL应使用MFC全局函数AfxLoadLibrary而不是WIN32API中的LoadLibrary。

AfxLoadLibrary最终也调用了LoadLibrary这个API,但是在调用之前进行了线程同步的处理。

  AfxLoadLibrary的函数原型与LoadLibrary完全相同,为:

HINSTANCEAFXAPIAfxLoadLibrary(LPCTSTRlpszModuleName);

  与之相对应的是,MFC应用程序应使用AfxFreeLibrary而非FreeLibrary卸载MFC扩展DLL。

AfxFreeLibrary的函数原型也与FreeLibrary完全相同,为:

BOOLAFXAPIAfxFreeLibrary(HINSTANCEhInstLib);

  假如我们把上例中的“调用DLL”按钮单击事件的消息处理函数改为:

voidCLoadExtDllDlg:

:

OnDllcallButton()

{

 HINSTANCEhDll=AfxLoadLibrary("ExtDll.dll");

 if(NULL==hDll)

 {

  AfxMessageBox("MFC扩展DLL动态加载失败");

  return;

 }

 CExtDialogextDialog;

 extDialog.DoModal();

 AfxFreeLibrary(hDll);

}

  则工程会出现link错误:

LoadExtDllDlg.obj:

errorLNK2001:

unresolvedexternalsymbol"__declspec(dllimport)public:

virtual__thiscallCExtDialog:

:

~CExtDialog(void)"(__imp_?

?

1CExtDialogUAE@XZ)

LoadExtDllDlg.obj:

errorLNK2001:

unresolvedexternalsymbol"__declspec(dllimport)public:

__thiscallCExtDialog:

:

CExtDialog(classCWnd*)"(__imp_?

?

0CExtDialogQAE@PAVCWnd@Z)

  提示CExtDialog的构造函数和析构函数均无法找到!

是的,对于派生MFC类的MFC扩展DLL,当我们要在应用程序中使用DLL中定义的派生类时,我们不宜使用动态加载DLL的方法。

  6.4MFC扩展DLL加载MFC扩展DLL

  我们可以在MFC扩展DLL中再次使用MFC扩展DLL,但是,由于在两个DLL中对于AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA宏的定义都是输出,这会导致调用的时候出现问题。

  我们将会在调用MFC扩展DLL的DLL中看到link错误:

errorLNK2001:

unresolvedexternalsymbol….......

  因此,在调用MFC扩展DLL的MFC扩展DLL中,在包含被调用DLL的头文件之前,需要临时重新定义AFX_EXT_CLASS的值。

下面的例子显示了如何实现:

//临时改变宏的含义“输出”为“输入”

#undefAFX_EXT_CLASS

#undefAFX_EXT_API

#undefAFX_EXT_DATA

#defineAFX_EXT_CLASSAFX_CLASS_IMPORT

#defineAFX_EXT_APIAFX_API_IMPORT

#defineAFX_EXT_DATAAFX_DATA_IMPORT

//包含被调用MFC扩展DLL的头文件

#include"CalledDLL.h"

//恢复宏的含义为输出

#undefAFX_EXT_CLASS

#undefAFX_EXT_API

#undefAFX_EXT_DATA

#defineAFX_EXT_CLASSAFX_CLASS_EXPORT

#defineAFX_EXT_APIAFX_API_EXPORT

#defineAFX_EXT_DATAAFX_DATA_EXPORT

6.5MFC扩展DLL导出函数和变量

  MFC扩展DLL导出函数和变量的方法也十分简单,下面我们给出一个简单的例子。

  我们在MFC向导生成的MFC扩展DLL工程中添加gobal.h和global.cpp两个文件:

//global.h:

MFC扩展DLL导出变量和函数的声明

extern"C"

{

 intAFX_EXT_DATAtotal;//导出变量

 intAFX_EXT_APIadd(intx,inty);//导出函数

}

//global.cpp:

MFC扩展DLL导出变量和函数定义

#include"StdAfx.h"

#include"global.h"

extern"C"inttotal;

intadd(intx,inty)

{

 total=x+y;

 returntotal;

}

  编写一个简单的控制台程序来调用这个MFC扩展DLL:

#include

#include单击此处下载本工程)。

  我们知道static控件所对应的CStatic类不具备设置背景和文本颜色的接口,这使得我们不能在对话框或其它用户界面上自由灵活地修改static控件的颜色风格,因此我们需要一个提供了SetBackColor和SetTextColor接口的CStatic派生类CMultiColorStatic。

 

  这个类的声明如下:

classAFX_EXT_CLASSCMultiColorStatic:

publicCStatic

{

 //Construction

 public:

  CMultiColorStatic();

  virtual~CMultiColorStatic();

  //Attributes

 protected:

  CStringm_strCaption;

  COLORREFm_BackColor;

  COLORREFm_TextColor;

  //Operations

 public:

  voidSetTextColor(COLORREFTextColor);

  voidSetBackColor(COLORREFBackColor);

  voidSetCaption(CStringstrCaption);

  //Generatedmessagemapfunctions

 protected:

  afx_msgvoidOnPaint();

  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类添加“设置文本颜色”接口

voidCMultiColorStatic:

:

SetTextColor(COLORREFTextColor)

{

 m_TextColor=TextColor;//设置文字颜色

}

//为CMultiColorStatic类添加“设置背景颜色”接口

voidCMultiColorStatic:

:

SetBackColor(COLORREFBackColor)

{

 m_BackColor=BackColor;//设置背景颜色

}

//为CMultiColorStatic类添加“设置标题”接口

voidCMultiColorStatic:

:

SetCaption(CStringstrCaption)

{

 m_strCaption=strCaption;

}

//重画Static,颜色和标题的设置都依靠于这个函数

voidCMultiColorStatic:

:

OnPaint()

{

 CPaintDCdc(this);//devicecontextforpainting

 CRectrect;

 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控件设置为“红色”、“蓝色”和“绿色”。

图17扩展的CStatic类调用演示

  下面看看应如何编写与这个对话框对应的类。

  包含这种Static的对话框类的声明如下:

#include"..\MultiColorStatic.h"

#pragmacomment(lib,"ColorStatic.lib")

//CCallDllDlgdialog

classCCallDllDlg:

publicCDialog

{

 public:

  CCallDllDlg(CWnd*pParent=NULL);//standardconstructor

  enum{IDD=IDD_CALLDLL_DIALOG};

  CMultiColorStaticm_colorstatic;//包含一个CMultiColorStatic的实例

 protected:

  virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport

  HICONm_hIcon;

 //Generatedmessagemapfunctions

 //{{AFX_MSG(CCallDllDlg)

 virtualBOOLOnInitDialog();

 afx_msgvoidOnSysCommand(UINTnID,LPARAMlParam);

 afx_msgvoidOnPaint();

 afx_msgHCURSOROnQueryDragIcon();

 afx_msgvoidOnRedButton();

 afx_msgvoidOnBlueButton();

 afx_msgvoidOnGreenButton();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

  下面是这个类中与使用CMultiColorStatic相关的主要成员函数:

voidCCallDllDlg:

:

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

}

BOOLCCallDllDlg:

:

OnInitDialog()

{

 …

 //TODO:

Addextrainitializationhere

 //初始static控件的显示

 m_colorstatic.SetCaption("最开始为黑色");

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

 returnTRUE;//returnTRUEunlessyousetthefocustoacontrol

}

//设置static控件文本颜色为红色

voidCCallDllDlg:

:

OnRedButton()

{

 m_colorstatic.SetCaption("改变为红色");

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

 Invalidate(TRUE);//导致发出WM_PAINT消息

}

//设置static控件文本颜色为蓝色

voidCCallDllDlg:

:

OnBlueButton()

{

 m_colorstatic.SetCaption("改变为蓝色");

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

 Invalidate(TRUE);//导致发出WM_PAINT消息

}

//设置static控件文本颜色为绿色

voidCCallDllDlg:

:

OnGreenButton()

{

 m_colorstatic.SetCaption("改变为绿色");

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

 Invalidate(TRUE);//导致发出WM_PAINT消息

}

  至此,我们已经讲解完成了所有类型的动态链接库,即非MFCDLL、MFC规则DLL和MFC扩展DLL。

下一节将给出DLL的三个工程实例,与读者朋友们共同体会DLL的应用范围和使用方法。

资料引用:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 电大

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1