实现MFC扩展DLL中导出类和对话框
中国学生网 2006-03-03 07:30:11 作者:江上飞鸟 来源:vckbase
如果要编写模块化的软件,就要对对动态链接库(DLL)有一定的了解,本人这段时间在修改以前的软件时,决定把重复用的类和对话框做到DLL中,下面就从一个简单的例子讲起,如何实现MFC扩展DLL中导出类和对话框。
一、创建MFC扩展DLL
步骤:
运行Visual Studio 6.0->File->New...->Projects;
选择Mfc AppWizard(dll),在右边Projectname下输入ExportClass,单击“下一步”;
选择Mfc Extension DLL (using share MFC DLL) 单击“finish”;
以上完成建立扩展DLL的框架,下面接着建立输出类:
Insert-> New Class...在打开的对话框中,"Class Type" 选择"GenericClass",Class Name 中输入
CDogClass(当然你可以用其它的名称,我喜欢小狗,所有用它了,在"Base Class"下输入CObject,然后"OK";
为类添加两个测试用的变量 int m_nNum;CString m_sData;完全的类信息如下:
DogClass.h头文件:
class CDogClass : public CObject |
编辑DogClass.h头文件修改下面一行;class AFX_EXT_CLASS CDogClass : public CObject
以上完成类的建立,下面建立输出对话框;Insert-> Resouce...新建立一个对话框,添加两个编辑框IDC_EDIT1,IDC_EDIT2,然后建立CDlgDog对话框类并为两编辑框添加int m_nNum和CString m_sData的变量。
在DogClass.cpp的#include"DogClass.h"下加入#include "DlgDog.h"
在DogClass类中添加int ShowDlg();函数用来调用对话框,并在int CDogClass::ShowDlg()中添加如下代码:
CDlgDog dlg; |
然后编译Dll,会发现有几个错误,不用怕,好解决的,首先,去掉DlgDog.cpp中的 #include “\ add additionalincludes here”这一行;其次,在stdax.h中加入include "resource.h",再编译,OK。
二、建立DLL 测试程序
步骤:
新建一个基于对话框的MFC应用程序,添加一按钮IDC_BUTTON1,并在按钮事件中添加如如下代码:
void CTestExportClassDlg::OnButton1() |
从ExportClass文件目录拷贝DogClass.h和ExportClass.lib文件到测试程序目录下;
在TestExportClassDlg.cpp中加入#include“DogClass.h”行;往连接程序的导入库中添加ExportClass.lib,在VS的Project->Settings下的Setting For选择All Configuration.,然后在下面的页面Object/Library Conttrol中加入ExportClass.lib;
别忘了把ExportClass.dll复制到系统目录或当前应用程序目录;然后编译就OK了。
在 Visual C++ 中建立 MFC 扩展 DLL
减小字体增大字体
在 Visual C++ 中建立 MFC 扩展 DLL我们编写了一个扩展类的样例并将其封装在 DLL 中以向你演示该过程。有经验的 Windows 编程人员都逐渐放弃了 Windows SDK,而转向能为 Windows 内置的低级机制提供高级抽象的开发环境。这种转移的一个主要受益者是 Visual C++,它依靠 MFC 库来提供 Windows API 的面向对象的视图。 MFC 是经验丰富的编程人员掌握的有力工具,但它离完美还相距甚远。事实上,我所认识的以 MFC 编程为谋生手段的人都开发了他或她自己的扩展集合,他们以 MFC 类作为基础类来派生自己的类。这毕竟是 C++ 的威力。如果某个类不能满足你的需求 ( 而且如果它恰好可以作为设计的开始 ),你可以从它自由地派生新类并修改你不喜欢的部分。 假设你编写了一个 MFC 扩展集合,并愿意与公司的其它开发人员共享。你该如何封装这些扩展呢?你可以分发源代码文件或与 Visual C++ 组件库(Component Gallery)兼容的组件。或许你可以象 MFC 那样在 DLL 中封装你的扩展。就象传统的 DLL 能够导出函数一样, MFC 扩展 DLL 可以导出类。任何动态链接到 MFC DLL 的应用程序都能动态链接到 MFC 扩展 DLL。作为开发者,你只需使其包括必要的头文件并在应用程序的链接列表中添加 DLL 导入库。 编写 MFC 扩展 DLL 困难吗?有了 Visual C++ 和 MFC 的支持,这实际非常轻松。本文解释了如何创建 MFC 扩展 DLL 来弥补 MFC 的 CToolTipCtrl 类的明显不足。一旦意识到其简便性,你会忍不住亲自编写几个 MFC 的扩展。 编写 MFC 扩展 DLL 从理论角度而言, MFC 的 CTool-TipCtrl 类简化了将提示信息(ToolTip)与对话框的控件或窗口的任意区域相关联的过程。 ( 提示信息是当鼠标光标停滞于工具栏按钮或其它 UI 对象时弹出的小型帮助文本窗口。 ) 但有个问题尚待解决。由于 CToolTipCtrl::AddTool 不能自动成为提示信息依附的窗口的子类,因此鼠标事件必须手工转交给提示信息控制。这通常意味着你必须自己给窗口建立子类。 如果你给 CToolTipCtrl 对象下的提示信息控制传送了正确的标志,它应该能给自己创建子类 ―― 这显然是被 MFC 设计组忽略的功能。幸运的是,该疏忽并不难以纠正。只要从 CToolTipCtrl 类中派生出一个类,用类似的函数代替 CToolTipCtrl::AddTool 即可,该函数的 TTM_ADDTOOL 消息使用 TOOLINFO 结构,它的 uFlags 域中包含 TTF_SUBCLASS 标志。更好的方式是用两个函数代替它:它们分别给子窗口和矩形窗口区域添加提示信息。 AddTool 函数同时支持两者,但在语法结构上创建提示信息的两种方法截然不同。 图 1 和图 2 显示了名为 CToolTip-CtrlEx 的 CToolTipCtrl 的派生类的源代码。该派生类给它继承的内容添加了两个函数,其一 CToolTipCtrl::AddWindow 将提示信息与子窗口相关联,其二 AddRectangle 使提示信息依附于窗口的矩形区域。这两个函数都使用了 TTF_SUBCLASS 标志以使提示信息的创建过程尽可能简单。假设 m_tooltipCtrl 是 CToolTipCtrlEx 对象,给控制 ID 为 IDC_BUTTON 的按钮添加提示信息就非常容易了: m_tooltipCtrl.AddWindow ( GetDlgItem (IDC_BUTTON), "Enter tooltip text here!"); 如何将 CToolTipCtrlEx 类封装至 DLL 呢?以下是在 Visual C++ 4.x 中的详细步骤: 1. 启动 Visual C++ 并通过从 File 菜单选择 New 来创建新项目,双击 Project Workspace。在 New Project Workspace 的 Name 框中输入 “MfcExt”( 不带引号 )。在 Type 框中选择 MFC AppWizard(dll)。然后点击 Create 按钮。 2. 在 AppWizard 的 Step 1 对话框中,通过在“What type of DLL would you like to create?” 项中选择“MFC Extension DLL(using shared MFC DLL)”。点击 Finish 按钮,然后点击 OK 产生 DLL 的初始代码。注意“MFC Extension DLL” 后括弧中显示的“using shared MFC DLL”。当你编写 MFC 扩展 DLL 时,不能选择静态链接至 MFC。 DLL 必须动态链接到 MFC 库。 3. 弹出 ClassWizard 并点击 Add Class 按钮。选择 New 打开 Create New Class 对话框。在其中标有“Base class” 的框中选择 CToolTipCtrl,在标有“Name” 的框中输入“CToolTipCtrlEx”。使用 Change 按钮将文件名改为 Tooltip.h 和 Tooltip.cpp。(改变文件名并不是绝对必要的,我这样做是为了避免长文件名。)不要选中“Add to Component Gallery” 框以节省磁盘空间。点击 Create 命令 ClassWizard 执行类派生,而后点击 OK 退出 ClassWizard。 4. 如图 2 所示,给 CToolTipCtrlEx 类添加成员函数 AddWindow 和 AddRectangle。由于这两个函数要在 CToolTipCtrlEx 外被访问,因此确定它们都是 public 的。技巧:在 Visual C++ 中给类添加成员函数的简便方法是在 ClassView 窗口中右击类名,并从快捷菜单中选择 Add Function。 5. 在 ClassView 窗口中,双击 CToolTipCtrlEx 打开类的头文件。在类说明的 class 关键字后添加 AFX_EXT_CLASS(参见图 1)。 6. 建立项目。你将产生两个重要文件: DLL 本身(Mfcext.dll)以及 DLL 的导入库(Mfcext.lib)。导入库基本上是导出函数名的列表 ―― 或者,在本例中是一系列导出类。链接至导入库使应用程序能使用从 MFC 扩展 DLL 中导出的类,就如同包含类的库是静态链接的一样。与 Mfcext.lib 链接还使得 Windows 知道应用程序需要 Mfcext.dll 才能运行。 使用 MFC 扩展 DLL 创建使用 Mfcext.dll 的应用程序是轻而易举的。只要确保在使用 CToolTipCtrlEx 的每个类中包括 Tooltip.h 头文件,并且将 Mfcext.lib 添加至项目的链接库列表中即可。然后 CToolTipCtrlEx 就可以象普通 MFC 类那样使用了。当回答 AppWizard 的询问时一定要选择“As a shared DLL”,这样你的应用程序才能动态链接至 MFC。你可以通过从 Visual C++ 的 Build 菜单中选择 Settings 将 Mfcext.lib 添加至项目的链接列表中,点击 Link 标签并在标有“Object/library modules” 的框中输入 Mfcext.lib 的路径(参见图 3)。 ToolTest 是作为样例的应用程序,它在对话框中显示一个按钮。它动态链接至 Mfcext.dll 并使用 CToolTipCtrlEx。该应用程序是基于对话框的, dialog 类包含名为 m_tooltipCtrl 的 CToolTipCtrlEx 成员变量。对话框的 OnInitDialog 函数中的以下代码创建提示信息控制并给对话框的按钮设置提示信息: m_tooltipCtrl.Creat (this); m_tooltipCtrl.AddWindowTool ( GetDlgItem (IDC_EXIT), "Click here to close"); 当光标停在按钮上时,提示信息窗口中显示“Click here to close”。点击该按钮可以关闭应用程序。 你可以从 PC Magazine Online(www.pcmag.com)下载 ToolTest 和 Mfcext.dll 的完整源代码。从主页左侧的菜单中选择 Downloads,然后依次选择 PC Tech Archives 和文件 V16n15.zip。 CompuServe 的 Utilities/Tips 论坛(GO ZNT:TIPS)上也有该文件。我们的文件包含在该归档文件中。使用 PKUNZIP 的 -d 开关解压文件(Mfcext.zip 和 Tooltest.zip),以便 .ZIP 文件中的目录也能一同被解压。在运行 ToolTest 之前,将 Mfcext.dll 拷贝至 Windows 系统目录或 Tooltest.exe 所在的目录。否则,当执行 ToolTest 时, Windows 可能找不到 Mfcext.dll。如果你打算建立自己的 Tooltest.exe 版本,修改 Project Settings 对话框的“Object/library modules” 框的路径名,使 Visual C++ 能获悉在 PC 的何处寻找 Mfcext.lib 文件。 总结 创建 MFC 扩展 DLL 非常容易 ―― 只要你知道了该如何操作。当你给其它开发人员分发 MFC 扩展 DLL 时,不要忘记提供描述 DLL 中类的头文件以及相应的 .LIB 文件和 DLL 本身。此后开发人员就能充分利用你装配的扩展了。 |
VC++动态链接库编程之MFC扩展DLL 来源:qqread 作者:新书城收集整理 发布时间:2006-12-23 人气:268 | |
|
|
前文我们对非MFC DLL和MFC规则DLL进行了介绍,现在开始详细分析DLL的最后一种类型――MFC扩展DLL。 6.1概论
MFC扩展DLL与MFC规则DLL的相同点在于在两种DLL的内部都可以使用MFC类库,其不同点在于MFC扩展DLL与应用程序的接口可以是MFC的。MFC扩展DLL的含义在于它是MFC的扩展,其主要功能是实现从现有MFC库类中派生出可重用的类。MFC扩展DLL使用MFC 动态链接库版本,因此只有用共享MFC 版本生成的MFC 可执行文件(应用程序或规则DLL)才能使用MFC扩展DLL。 从前文可知,MFC规则DLL被MFC向导自动添加了一个CWinApp的对象,而MFC扩展DLL则不包含该对象,它只是被自动添加了DllMain 函数。对于MFC扩展DLL,开发人员必须在DLL的DllMain函数中添加初始化和结束代码。 从下表我们可以看出三种DLL对DllMain入口函数的不同处理方式: 对于MFC扩展DLL,系统会自动在工程中添加如下表所示的宏,这些宏为DLL和应用程序的编写提供了方便。像AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA这样的宏,在DLL和应用程序中将具有不同的定义,这取决于_AFXEXT宏是否被定义。这使得在DLL和应用程序中,使用统一的一个宏就可以表示出输出和输入的不同意思。在DLL中,表示输出(因为_AFXEXT被定义,通常是在编译器的标识参数中指定/D_AFXEXT);在应用程序中,则表示输入(_AFXEXT没有定义)。 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两个头文件。 图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类被导出。 |
VC++动态链接库编程之MFC扩展DLL 来源:qqread 作者:新书城收集整理 发布时间:2006-12-23 人气:268 | |
|
|
6.3 MFC扩展DLL的加载 6.3.1 隐式加载 我们在6.2工程所在的工作区中添加一个LoadExtDllDlg工程,用于演示MFC扩展DLL的加载。在LoadExtDllDlg工程中添加一个如图16所示的对话框,这个对话框上包括一个“调用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 | ||
VC++动态链接库编程之MFC扩展DLL 来源:qqread 作者:新书城收集整理 发布时间:2006-12-23 人气:269 | ||
|
|
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 <iostream.h> #include <afxver_.h> //AFX_EXT_DATA、AFX_EXT_API宏的定义在afxver_.h头文件中 #pragma comment ( lib, "ExtDll.lib" ) #include "..\global.h" int main(int argc, char* argv[]) { cout << add(2,3) << endl; cout << total; return 0; } 运行程序,在控制台上看到: 5 5 另外,在Visual C++下建立MFC扩展DLL时,MFC DLL向导会自动生成.def文件。因此,对于函数和变量,我们除了可以利用AFX_EXT_DATA、AFX_EXT_API宏导出以外,在.def文件中定义导出也是一个很好的办法。与之相比,在.def文件中导出类却较麻烦。通常需要从工程生成的.map文件中获得类的所有成员函数被C++编译器更改过的标识符,并且在.def文件中导出这些“奇怪”的标识符。因此,MFC扩展DLL通常以AFX_EXT_CLASS宏直接声明导出类。 6.6 MFC扩展DLL的应用 上述各小节所举MFC扩展DLL的例子均只是为了说明某方面的问题,没有真实地体现“MFC扩展” 的内涵,譬如6.2派生自CDialog的类也不具备比CDialog更强的功能。MFC扩展DLL的真实内涵体现在它提供的类虽然派生自MFC类,但是提供了比MFC类更强大的功能、更丰富的接口。下面我们来看一个具体的例子(单击此处下载本工程)。 我们知道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控件设置为“红色”、“蓝色”和“绿色”。 图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的应用范围和使用方法。 |