版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
动态链接库和ActiveX开发第09章本章主要内容9.2编写自己的ActiveX控件9.1编写自己的DLL9.1编写自己的DLL9.1.1DLL概述9.1.2MFC中DLL的分类9.1.3DLL中的导入导出函数9.1.4DLL中的数据与资源9.1.5DLL与应用程序的链接9.1.6DLL开发举例9.1.1DLL概述
比较大的应用程序都是由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作完成整个软件系统的工作,其中可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程序文件中,会带来一些不足:一是增加了应用程序的大小,占用更多的磁盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费;二是在编写大的应用程序时,每次修改重建都必须编译所有的源代码,增加了编译过程的复杂性,也不利于阶段性的单元测试。Windows平台提供了一种较为有效的编程和运行环境,开发者可以将独立的程序模块创建为DLL(DynamicLinkableLibrary)文件,并可对它们进行单独编译和测试。运行时,只有当EXE程序调用这些DLL模块时,系统才会将它们装载到内存空间,这种方式不仅减少了EXE文件的大小和对内存空间的占用,而且使这些DLL模块同时被多个应用程序使用,Windows自身就将一些主要功能以DLL模块形式实现。9.1.1DLL概述一般来说,DLL是一种二进制文件(通常带有DLL扩展名),它由全局数据、服务函数和资源组成。在运行时被系统加载到进程的虚拟地址空间中,成为调用进程的一部分。如果与其它DLL没有冲突,该文件通常映射到进程虚拟地址空间的同一地址上。DLL模块中包含各种导出函数,用于向外界提供服务,Windows在加载DLL模块时,将进程中的函数调用与DLL文件的导出函数进行匹配。在Windows环境中,每个进程都复制了自己的读/写全局变量,如果想和其它进程共享内存,必须使用内存映射文件或者声明一个共享数据段,DLL模块需要的内存都是从运行进程的堆栈中分配的。
DLL编程越来越容易了,Windows大大简化了其编程模式,而且有各种向导和MFC类库支持,下面主要讨论如何在VS2010环境中使用MFC编写DLL。9.1.2MFC中DLL的分类带静态链接MFC的规则DLL
使用共享MFCDLL的规则DLLMFC扩展DLLVS2010MFCDLL向导对话框1、带静态链接MFC的规则DLL使用
该类DLL采用静态方式连接到MFC的动态连接库,它的特点是在源文件里有一个继承自CWinApp的类。这种DLL应用程序的导出函数可以被任何Windows应用程序调用,因为该动态库包含了它所使用的所有MFC函数。其导出函数具有如下形式:
extern“C”EXPORTYourExportedFunction();
如果没有extern“C”修饰,导出函数仅能被C++代码调用,DLL应用程序从CWinApp派生,但没有消息循环。它自动生成def文件,在派生类的InitInstance和ExitInstance成员函数中完成初始化和结束工作。2.使用共享MFCDLL的规则DLL
它和静态链接的DLL一样,也是内部使用MFC的DLL,导出函数是标准的C语言接口,可以被MFC和非MFC应用程序使用,具有def文件,在CWinApp派生类的InitInstance和ExitInstance成员函数中进行初始化和结束工作。这种DLL建立时使用的是MFC的动态共享库,但它的导出函数可以被任何Windows应用程序所调用,包括使用MFC的应用程序。所有从DLL导出的函数应该加上如下语句:AFX_MANAGE_STATE(AfxGetStaticModuleState())该宏用于正确切换MFC模块状态,AfxGetStaticModuleState函数用于获取模块状态,这个宏必须出现在任何调用MFC语句之前,包括声明对象、变量之前,因为它们的构造函数可能会调用MFCDLL,该宏在调用MFCDLL导出函数时保证模块状态的正确以及能访问到有效资源(如DLL中的对话框等),而且MFC模块结束时,自动恢复到以前的模块状态。提示:AFX_MANAGE_STATE宏不能用在静态链接的MFCDLL和MFC扩展DLL中。如果要在动态链接MFCDLL中使用MFCOLE功能,则必须在DLL的InitInstance中调用AfxOleInitModule。同样,如果使用MFC数据库或DAO支持,必须调用AfxDbInitModule,使用MFCSocket支持,则要调用AfxNetInitModule。3.MFC扩展DLL
MFC扩展DLL,用来导出从MFC继承的类,也就是说,用这种类型的动态连接库,可以用来导出一个从MFC继承的类。它的导出函数只可以被使用MFC且动态链接到MFC的应用程序所使用。可以从MFC继承用户所需要的类,并把它提供给客户应用程序,也可给客户应用程序提供MFC或MFC继承类的对象指针。MFC扩展DLL使用MFC动态链接方式创建,而且只能用于MFC类库所编写的应用程序。MFC扩展DLL和前两种DLL不同,它没有从CWinApp派生应用程序类。因此,程序员必须在DllMain函数(DLL的主函数)中为自己的动态链接库编写代码以实现DLL的初始化和结束清理工作。总之,MFC扩展DLL具有几个方面特征:(1)没有应用程序对象(派生自CWinApp);(2)必须有一个DllMain函数;(3)DllMain必须调用AfxInitExtensionModule函数,并且检查其返回值,如果返回0,DllMmain也返回0;(4)如果想导出CRuntimeClass类型的对象或者资源(Resources),则需要提供一个初始化函数用来创建CDynLinkLibrary对象,并且初始化函数也要导出;(5)使用MFC扩展DLL的MFC应用程序必须有一个CWinApp派生类,在该派生类的InitInstance成员函数中调用MFC扩展DLL的初始化函数。9.1.3DLL中的导入导出函数
在动态链接库中,定义的函数有两种:导出函数(exportfunction)和内部函数(internalfunction),导出函数可以被其它模块调用,内部函数只能在动态库内部使用。DLL文件中包含一个导出函数表,这些导出函数通过它们的符号名和整型标识号与外界联系,函数表中还包含了DLL中函数的地址。当应用程序加载DLL模块时,它并不知道调用函数的实际地址,但它知道函数的符号名和标识号,动态链接在加载DLL模块时动态建立一个函数调用与函数地址的对应表,如果重新编译DLL文件,并不需要修改应用程序,除非改变了导出函数的符号名和参数列表。简单的DLL文件只为应用程序提供导出函数,复杂的DLL文件除了提供导出函数外,还调用其它DLL文件中的函数,这样,一个动态链接库既有导出函数,又有导入函数。这并不会产生任何问题,因为动态链接过程可以正确处理交叉引用。从DLL中导出函数(1)使用DEF文件(2)使用关键字_declspec(dllexport)(3)使用AFX_EXT_CLASS宏 使用关键_declspec(dllexport)不但能导出函数,而且可以导出数据、类或者类的成员函数,AFX_EXT_CLASS宏主要用来导出类。(1)使用DEF文件
1.模块定义文件(DEF)是由一个或多个用于描述DLL属性的语句组成的文本文件:
NAME语句:指出生成DLL的文件名
LIBRARY语句:指出DLL的内部名字,这个语句告诉链接器生成的是DLL
DESCRIPTION语句:描述DLL的用途
STACKSIZE语句:设置堆栈大小
SECTIONS语句:设置段属性
VERSION语句:给出DLL的版本号
;:是注释语句。(2)使用关键字_declspec(dllexport)
2.使用关键字_declspec(dllexport),可以从DLL中导出数据、函数、类或者类的成员函数。在DLL代码中,必须明确声明导出函数。__declspec(dllexport)intMyFunction(intn);相应地,在客户应用程序中,也必须明确声明相应的导入函数:__declspec(dllimport)intMyFuncition(intn);这个关键字不仅可以导出函数,而且可以导出类。用于导出类时,将导出类中所有public成员函数和成员变量。class_declspec(dllexport)CMyExportClass:publicCObject{ //…}仅有导入和导出声明,并不能使客户应用程序的函数调用链接到相应的DLL文件,客户应用程序必须为链接程序指定所需要的输入库(LIB文件),而且客户应用程序至少包含对DLL中函数的一次调用。(3)使用AFX_EXT_CLASS宏
3.使用AFX_EXT_CLASS宏,MFC扩展DLL使用AFX_EXT_CLASS宏导出类,链接这种DLL的客户应用程序或者其它DLL,也必须使用这个宏导入类。MFC向导生成的应用程序框架支持在DLL和客户应用程序中使用这个宏。利用AFX_EXT_CLASS宏,MFC扩展DLL和客户应用程序就可以使用相同的头文件,给开发工作带来了便利。这个宏可以导出整个类,如:
classAFX_EXT_CLASSCMyExportClass:putlicCObject{….}也可以导出类中的某个成员:
classCExampleDialog:publicCDialog
{
public:
AFX_EXT_CLASSCExampleDialog();
AFX_EXT_CLASSintDoModal();
………….
//
………….
}9.1.4DLL中的数据与资源
DLL既可以导出函数、类,也可以导出数据和资源供客户应用程序使用。导出数据。数据导出一般采用以下两种方法。(1)使用DEF文件的DATA关键字导出(2)用_declspec(dllexport)关键字导出(1)使用DEF文件的DATA关键字导出(1)使用DEF文件的DATA关键字导出,在DEF文件导出语句中,除了NONAME标志外,还有一个DATA标志,表明前面导出的不是函数,而是一个数据。例如:在DLL中定义了一个变量:
intnVariable=0;在DEF文件中用下列语句导出:
EXPORTS
nVariable@5DATA在客户应用程序中,用以下语句来使用DLL导出的数据:
externintnVariable; //必须和DLL导出的名字相同
printf(“Dll中的nVariable=%d”,*(int*)nVariable);这种方法使用的并不是变量本身,而是DLL中导出变量的指针,应用程序必须通过强制指针类型转换来使用,在客户应用程序中也可以使用_declspec(dllimport)关键字来导入DLL导出的变量。提示:在VisualC++早期版本中,用户也可以使用CONSTANT关键字导出数据,用法和DATA关键字一样。在VS2010中,建议使用DATA关键字。(2)用_declspec(dllexport)关键字导出
用_declspec(dllexport)关键字导出,可以不使用DEF文件,在源程序中使用_declspec(dllexport)关键字来修饰要导出的变量。在客户应用程序中使用_declspec(dllimport)关键字来导入DLL中导出的变量。可以看出,使用_declspec(dllexport)和_declspec(dllimport)导出导入数据是最简单的方法。DLL和客户应用程序一样,也可以拥有自己的资源。如果编写的DLL程序仅仅是用于存放共享资源,供其它程序使用,也就是说,在DLL中只有资源,如:图标、位图、字符串、声音、视频、对话框等,那么,这种DLL就属于纯资源DLL。使用这种纯资源DLL可以缩减可执行文件的大小,而且DLL中的资源可以被其它应用程序所共享,提高了性能。纯资源DLL编写比普通DLL编写要简单得多,首先创建一个WIN32DLL项目,注意,不是MFCDLL,然后创建一个资源文件(.RC),并将其添加到资源DLL项目中,最后添加一个初始化DLL的C++文件。
(2)用_declspec(dllexport)关键字导出extern"C"BOOLWINAPIDllMain(HINSTANCEhInstance,DWORDdwReason,LPVOID){return1;}这是纯资源DLL所必需的代码,保存这个文件为C++源文件,编译这个资源DLL。在客户应用程序中调用这个DLL时,使用LoadLibrary函数装入资源DLL,使用FindResource和LoadResource装入各种资源,或者使用下列的特定的资源装入函数装入特定的资源:FormatMessage、LoadAccelerators、LoadBitmapLoadCursor、LoadIcon、LoadMenu、LoadString当资源使用结束时,应用程序必须调用FreeLibrary函数释放资源。9.1.5DLL与应用程序的链接
DLL不能单独执行,必须和客户应用程序链接才能使用。客户应用程序的导入函数与DLL文件中的导出函数有2种链接方式:隐式链接(ImplicitLinking)和显式链接(ExplicitLinking)。所谓隐式链接是指在应用程序中不必指明DLL文件的存储路径,程序员也不必关心DLL文件的实际装载,而显式链接正好相反。
1.隐式链接方式(ImplicitLinking)
2.显式链接方式(ExplicitLinking)
1.隐式链接方式(ImplicitLinking)
程序员在建立DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件,该文件包含了每一个导出函数的符号名和可选的标识号,但并不包含实际代码。LIB文件作为DLL的替代文件被编译到客户应用程序项目中。当通过动态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件中的导出符号相匹配,这些符号或标识号就进入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名(不是完整的路径名),链接程序将其存储在EXE文件内部。在应用程序运行过程中,需要加载DLL文件时,Windows就会根据这些信息发现并加载DLL,然后通过符号名或标识号实现对DLL中函数的动态链接。
2.显式链接方式(ExplicitLinking)
这种方式对于集成化的开发语言(例如VC、VB)比较适合。有了显式链接,使用DLL的程序就不必使用导入文件,而是用LoadLibrary或MFC提供的AfxLoadLibrary显式的将需要的动态链接库装入内存,这两个函数的参数就是动态链接库的文件名,接下来用GetProcAddress()函数得到导出函数的地址,也就是导入的函数,GetProcAddress函数将符号名或标识号转换为DLL内部地址。至此,就可以像使用应用程序自身的函数一样,自由地调用导入函数了,在应用程序退出之前,需要用FreeLibrary或MFC提供的AfxFreeLibrary函数释放动态链接库。例如,有这样一个导出函数:extern"C"__declspec(dllexport)doubleSquareRoot(doubled);下面的代码就是在客户应用程序中对该导出函数的显式链接。typedefdouble(SQRTPROC)(double);HINSTANCEhInstance;SQRTPROC*pFunction;VERIFY(hInstance=::LoadLibrary("c:\\winnt\\system32\\mydll.dll"));VERIFY(pFunction=(SQRTPROC*)::GetProcAddress(hInstance,"SquareRoot"));doubled=(*pFunction)(81.0); //调用该DLL中的函数在隐式链接方式中,所有被应用程序调用的DLL文件都会在应用程序文件加载时被加载到内存,如果采用显式链接方式,程序员就可以决定何时加载DLL、何时卸载DLL。例如,应用程序可以根据用户选择的语种,加载与之对应的DLL文件,对于选择了英语的用户,加载英语字符串资源DLL,对于选择了西班牙语的用户,则加载西班牙语字符串资源。
Windows遵循下列的次序来搜索和定位DLL:(1)EXE文件所在目录(2)进程当前工作目录(3)Windows系统目录(4)Windows目录(5)列在Path环境变量中的一系列目录在使用MFC开发DLL相关应用程序时,对于初学者,建议采用隐式链接。9.1.6DLL开发举例
在这个实例中,需要开发3个应用程序模块:(1)S9_1是一个DLL程序,它导出一个函数。(2)S9_2也是一个DLL程序,它导出一个类。(3)S9_3是一个客户应用程序,在它里面,调用了S9_1、S9_2导出的函数和类。在开发过程中,通过具体操作对本章的基本概念和理论进行详细说明,帮助读者理解和掌握这些概念和技术。
1.S9_1使用“带静态链接MFC规则的DLL导出函数(1)用MFCDLL向导创建动态链接库项目S9_1。在VS2010主界面菜单上选择“文件|新建|项目”菜单项,打开“新建项目”对话框,在左侧选择VisualC++,右侧选择MFCDLL,项目名称输入S9_1,点击“确定”按钮,弹出“MFCDLL向导”对话框,选中“带静态链接MFC的规则DLL”单选框,如图9-2所示,其余保持默认,点击“完成”按钮,生成MFCDLL应用程序框架。
(2)修改所生成项目的头文件S9_1,加入对导出函数的声明。
(3)修改所生成项目的实现文件S9_1.cpp,添加导出函数的实现。(4)编译链接,生成动态链接库,所生成的DLL文件在后面的S9_3项目中使用。
2.S9_2使用MFC扩展DLL导出一个类,导出类使用AFX_EXT_CLASS宏。(1)利用MFCDLL向导创建S9_2动态链接库项目。(2)设计CDrawText类。(3)为CDrawText类添加成员变量。(4)为CDrawText类添加成员函数。(5)编译链接,生成S9_2.DLL动态链接库,供S9_3应用程序使用。3.S9_3项目的创建步骤(1)创建S9_3项目。(2)将当前项目所需要的S9_1.dll、S9_2.dll、S9_1.lib、S9_2.lib文件加入进来。(3)添加菜单资源,并添加命令消息响应函数。(4)导入S9_1.dll中的函数AddFunction()。(5)向S9_3项目导入S9_2.dll中的类CDrawText。(6)修改CS9_3Doc类的头文件和C++文件,为使用CDrawText类的对象作准备。(7)使用从S9_2导出的类CDrawText。(8)修改CS9_3View::OnDraw函数。运行界面读者可以把S9_2.dll的功能扩充,在编写程序的同时,要注意DLL的特点,只要DLL对外提供的接口(导出函数、类、数据以及供其它程序使用的资源等)保持不变,其内部实现就不会影响客户应用程序的开发和实现。9.2编写自己的ActiveX控件9.2.1ActiveX控件的事件、属性和方法9.2.2ActiveX控件开发实例9.2.1ActiveX控件的事件、属性和方法
ActiveX是Microsoft的一个术语,它指一组包括控件、DLL、ActiveX文档的组件,通常以动态链接库的形式存在,ActiveX控件必须提供属性名、方法名以及参数,以便容器可以存取和改变ActiveX控件的属性,ActiveX控件的数据输入和函数调用必须通过容器,因此ActiveX控件具备以下特点。1.属性表示ActiveX控件状态的变量。ActiveX控件的属性有两种访问方式:使用成员变量和使用Get/Set方法,其属性又分为2种:固有属性(Stockproperties):固有属性是已经被COleControl类实现了的属性,在VS2010中,应用向导支持的固有属性有:ActiveX控件背景色(BackColor)、标题(Caption)等,固有属性是带有普遍性的一些属性。自定义属性(Customproperties):程序员自己定义的属性,是和具体控件相关的属性。例如,如果编写了播放avi文件的控件,则当前播放的文件名就是自定义属性。2.方法:控件容器可以调用的ActiveX控件方法。其方法分为2种:固有方法:已经被COleControl类实现的方法。COleControl类支持两个固有方法:DoClick方法和Refresh方法,其中,DoClick方法用于发送一个Click事件,而Refresh方法则用于立即更新ActiveX控件窗口。自定义方法:程序员自己定义的方法。例如,对于播放avi文件的控件,Play、Stop等均为自定义方法。3.事件:由ActiveX控件发送给控件容器的通知消息,ActiveX控件通过事件告诉控件容器某个事件发生了,如属性参数改变、用户单击、双击动作等,容器根据具体事件作出不同的响应,事件也分为2种:固有事件:已经由COleControl定义的事件,共有10种,典型的固有事件如Click事件,该事件为用户单击ActiveX控件时由ActiveX控件发送的消息,COleControl类中还为每个固有事件提供了一个发送事件的函数,这些函数可用于模拟相应的事件。例如,FireClick()函数向控件容器发送Click事件。自定义事件:程序员自己定义的事件。例如,播放avi文件的控件,当avi文件播放完毕后向控件容器发送一个自定义事件——播放完毕,用于通知控件容器进行相应处理。9.2.2ActiveX控件开发实例1.创建项目2.添加固有属性3.添加自定义属性
1.创建项目(1)在VS2010中,通过菜单“文件|新建|项目…”,打开“新建项目”对话框,项目模板选择“MFCActiveX控件”,“名称”输入“S9_4”,选择项目保存位置,如图9-10所示。
(2)单击“确定”按钮,弹出“MFCActiveX控件向导”对话框,选择“控件名称”,可以看到所创建的ActiveX控件的名字为S9_4,如图9-11所示,读者也可以修改为有意义的名字,本实例不做修改,全部采用默认值,单击“完成”按钮,完成ActiveX项目的创建。1.创建项目
2.添加固有属性下面给S9_4控件添加设置背景色和前景色的功能。(1)单击“调试|选项和设置”,弹出“选项”对话框,如图9-12所示,选择“WorkflowDesigner|主题”,单击“新建”,弹出“ThemeConfiguration”对话框,如图9-13所示。(2)选择属性BackColor,弹出颜色对话框,选择合适的颜色。(3)单击确定按钮,返回到“选项”对话框,为控件增加了一个背景色属性。(4)重复(1)—(3),为控件添加前景色属性(ForeColor)。
(5)在控件的C++文件S9_4Ctl.cpp中,添加颜色属性页(6)在控件的OnDraw函数中,添加使用颜色属性的代码:
3.添加自定义属性(1)在VS2010环境的“类视图”标签中展开控件的库文件“S9_4Lib”,如图9-14所示,在“_DS9_4”节点上按鼠标右键,打开快捷菜单,从中选择“添加|添加属性”,打开“添加属性向导”对话框,如图9-15所示,为控件添加一个TextAlign属性,类型为LONG,访问方式为成员变量。(2)单击“完成”按钮,返回VS2010主界面。
(3)修改控件的文本对齐方式的消息响应函数
(4)接下来,需要修改自定义属性的对话框资源,在工作区的“资源视图”中展开对话框资源,双击Dialog|IDD_PROPPAGE_S9_4,打开对话框资源编辑器,删除原有的StaticText控件,添加3个单选按钮和一个分组框控件,将第一个单选按钮的Group属性设为TRUE,其余两个设置为FALSE,也就是将它们三个分为一组,4.为CS9_4Ctrl类添加一些额外变量
(1)在控件的头文件S9_4Ctl.h中添加以下私有成员变量。
(2)在控件的C++文件S9_4Ctl.cpp中,修改构造函数CS9_4Ctrl::CS9_4Ctrl(),对以上4个变量进行初始化。(3)修改控件的C++文件S9_4Ctl.cpp的CS9_4Ctrl::OnDraw函数,实现控件文本信息的输出。
5.为控件添加鼠标移动的消息响应函数
在VS2010开发环境中,通过类向导为CS9_4Ctrl类中添加
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论