八宝书库 > 文学其他电子书 > C语言实例教程(PDF格式) >

第84部分

C语言实例教程(PDF格式)-第84部分

小说: C语言实例教程(PDF格式) 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




    数时,只要新的导出函数的顺序值大于原有的导出函数,就没有 

    必要重新链接使用隐含链接的应用程序。相反,如果使用 

   __declspec(dllexport)来导出函数,如果向DLL中添加了新的函 

    数,使用隐含链接的应用程序有可以需要重新编译和链接。  



  l 使用DEF文件来导出函数,可以创建具有NONAME属性的DLL。具有 

   NONAME属性的DLL在导出表中仅包含了导出函数的顺序值,这种类 

    型的DLL在包括有大量的导出函数时,其文件长度要小于通常的 


…………………………………………………………Page 670……………………………………………………………

   DLL。  



  l 使用DEF文件从C++文件导出函数,应该在定义函数时使用extern  

   〃C〃或者在DEF文件中指定导出函数的decorated name。否则,由 

   于编译器所产生的decorated name是基于特定编译器的,链接到 

   该DLL的应用程序也必须使用创建DLL的同一版本的Visual C++来 

   编译和链接。  



  l 由于使用__declspec(dllexport)关键字导出函数不需要编写DEF 

   文件,因此,如果编写的DLL只供自己使用,使用__declspec 

   (dllexport)较为简单。  



    



  l 注意:  



  l MFC本身使用了DEF文件从MFCx0。DLL中导出函数和类。  



13。2。2 链接应用程序到DLL  



同样,链接应用程序到DLL也有两种方法:  



  l 隐含链接  



  l 显式链接  



隐含链接有时又称为静态加载。如果应用程序使用了隐含链接,操作 

系统在加载应用程序的同时加载应用程序所使用的DLL。显式链接有 

时又称为动态加载。使用动态加载的应用程序必须在代码中明确的加 

载所使用的DLL,并使用指针来调用DLL中的导出函数,在使用完毕之 

后,应用程序必须卸载所使用的DLL。  



同一个DLL可以被应用程序隐含链接,也可以被显式链接,这取决于 

应用程序的目的和实现。  



下面我们在分别讲述两种不同的链接方式之后再作对比。  



   (1) 使用隐含链接  



在使用隐含链接除了需要相应的DLL文件外,还必须具备如下的条 

件:  



  l 一个包括导出的函数或C++类的头文件  


…………………………………………………………Page 671……………………………………………………………

  l 一个输入库文件 (。LIB文件)  



通常情况下,我们需要从DLL的提供者那里得到上面的文件。输入库 

文件是在DLL文件被链接时由链接程序生成的。  



在 “13。2。1   DLL的结构和导出方式”中所创建的DLL:msgbox。dll所 

对应的头文件msgbox。h如下:  



#include   



extern 〃C〃 __declspec(dllimport) int MsgBox(  



// 消息框的文本  



LPCTSTR lpText=〃虽然这个例子有一些幼稚,但它工作得非常的好 !〃;  



// 消息框的标题  



LPCTSTR lpCaption=〃一个简单的例子〃;  



// 消息框的样式  



UINT uType=MB_OK);  



需要注意的是,这个msgbox。h文件和创建DLL时所使用msgbox。h是不 

同的,唯一的差别在于,创建DLL时的msgbox。h中使用的是 

__declspec(dllexport)关键字,而供应用程序所使用的msgbox。h 中 

使用的是__declspec(dllimport)关键字。无论创建DLL时使用的是 

DEF文件还是__declspec(dllexport)关键字,均可使用__declspec 

(dllimport)关键字从DLL中引入函数。引入函数时也可以省略 

__declspec(dllimport)关键字,但是使用它可以使编译器生成效率 

更高的代码。  



  l 注意:  



  l 如果需要引入的是DLL中的公用数据和对象,则必须使用 

    __declspec(dllimport)关键字。  



现在使用Microsoft  Developer  Studio创建一个Win32  Application 

工程,命名为tester。向工程中添加一个C++源文件,如 

tester。cpp。在tester。cpp文件中输入下面的代码:  



#include 〃msgbox。h〃 // 应将msgbox。h文件拷贝到工程tester的目录下。  



int WINAPI WinMain(HINSTANCE hInstance;  


…………………………………………………………Page 672……………………………………………………………

HINSTANCE hPrevInstance;  



LPSTR lpCmdLine;  



int nCmdShow)  



{  



return MsgBox();  



}  



在上面的代码中,MsgBox()函数的所有参数都使用了缺省值。  



  l 注意:  



  l 在编译之前,将上一步生成的msgbox。lib文件拷贝到tester工程 

    所在的目录下。然后单击菜单项Project|Settings。。。,将 

    msgbox。lib添加到Link选项卡下的Object/library modules文本 

    框中。如果忽略这一步,链接时将会导致错误。完成之后创建该 

    应用程序。  



如果现在运行该程序,将出现如图13。1所示的对话框。  



                                                 



                     图13。1 未找到DLL时出现的错误  



上面的对话框说明程序没有在指定的路径未找到所需要的DLL。  



一般情况下,程序在运行时,系统将按如下的顺序查找程序所使用的 

动态链接库:  



  l 系统预安装的DLL,如KERNEL32。DLL和USER32。DLL等  



  l 当前目录  



  l Windows的系统的目录,如WINNTsystem32  



  l Windows所在的目录,如WINNT  



  l 环境变量PATH中所指定的目录  


…………………………………………………………Page 673……………………………………………………………

                                            



                    图13。2 tester应用程序的运行结果  



如果Windows在上面的目录中未找到所需要的DLL,则弹出如图13。1所 

示的对话框。这里,我们把msgbox。dll文件拷贝到testerDebug 目录 

下,再运行应用程序,则出现如图13。2所示的对话框。  



    (2) 使用显式链接  



如果没有与DLL相关联的LIB文件,则必须使用显式链接。使用显式链 

接同样必须知道函数返回值的类型和所传递的参数个数、类型和顺 

序。与使用隐含链接不同的是,使用显式链接的应用程序在调用DLL 

中的导出函数前,必须使用LoadLibrary()函数加载DLL并得到一个模 

块句柄。然后使用该句柄调用GetProcAddress()函数获得所需调用的 

导出函数的指针,并通过该指针调用DLL中的导出函数,这种模式使 

用显式链接到DLL的应用程序不再需要相应的LIB文件。在使用完毕之 

后,还需调用FreeLibrary()函数释放加载的DLL。  



下面我们使用显式链接的方式来实现前面的例子。  



由于使用指针来调用DLL中的导出函数,所以本例中不再需要 

msgbox。h文件。  



在tester。cpp中添加的代码如下所示:  



#include   



typedef int (CALLBACK* DLLFUNC)(  



LPCTSTR lpText=〃虽然这个例子有一些简单,但它工作得非常的好 !〃;  



LPCTSTR lpCaption=〃一个简单的例子〃;  



UINT=MB_OK);  



int WINAPI WinMain(HINSTANCE hInstance;  



HINSTANCE hPrevInstance;  



LPSTR lpCmdLine;  



int nCmdShow)  



{  


…………………………………………………………Page 674……………………………………………………………

HINSTANCE hDLL;  



DLLFUNC MsgBox;  



hDLL = LoadLibrary(〃msgbox〃);  



if (hDLL != NULL)  



{  



MsgBox =   



(DLLFUNC)GetProcAddress(hDLL;〃MsgBox〃);  



return MsgBox();  



}  



}  



LoadLibrary()函数的参数是所调用的DLL的名字,这个名字不是放入 

输入库文件中的名字,而是DLL的文件名。如果文件的扩展名 

为。DLL,则可以省略。  



这个程序的运行结果同使用隐含链接的前一个程序一样,但它的内部 

实现是很不相同的。使用显式链接的应用程序加载时,所调用的DLL 

并不加载,只有当应用程序调用LoadLibray()时系统才加载相应的 

DLL,并在应用程序调用FreeLibrary()时卸载该DLL。使用隐含链接 

的应用程序调用DLL中的导出函数时,方法同调用一般的函数一样, 

而使用显式链接的应用程序必须使用指针来调用。由于使用了指针, 

因此在编译时不能验证参数的合法性,通过指针使用不合法的参数来 

调用DLL中的导出函数将会导致不可预料的后果。  



很明显,使用隐含链接的方式调用DLL中的导出函数要比使用显式链 

接方便得多。但在某些情况下我们必须使用显式链接。事实上,使用 

显式链接调用DLL提供了更大的灵活性。尤其在没有与DLL相对应的 

LIB文件时,我们只能使用显式链接来调用DLL中的导出函数,并且, 

只要我们使用函数名作参数来调用GetProcAddress(),在更新DLL 

时,就没有必要重新链接应用程序。另外,使用隐含链接的方式的应 

用程序加载DLL时如果发生错误 (如DLL文件未找到或是DLL中的 

DllMain()函数初始化失败)时,应用程序将被终止,而使用显式链 

接的应用程序则可以使用如上面的例子中所给出的方法来避免出现这 

种情况 (可以使用所创建的两个不同版本的tester程序来验证这一 

点)。  


…………………………………………………………Page 675……………………………………………………………

由于应用程序调用LoadLibrary()函数时才加载DLL,因此使用显式链 

接的应用程序的加载速度要比使用隐含链接的应用程序快。使用显式 

链接的另一个好处是,应用程序可以在运行时决定所加载的DLL。  



但是要记住,由于使用了指针来传递应用程序的参数,因此编译器在 

编译时无法确认应用程序所传递的参数类型是否合法。传递不合法的 

参数给DLL中的导出函数的一件危险的事。在程序调试的过程中我们 

一定需要注意这一点。  



          第三节 使用动态链接连库扩展MFC  



我们还可以使用DLL来实现从MFC派生的一些可重用类,这种动态链接 

库一般称作MFC扩展动态链接库 (MFC Extension DLL)。正如这个名称 

所暗示的那样,通过这种方式我们可以扩展MFC所包括的内容,使得 

使用MFC编程更加的方便。此外,如果需要在应用程序和DLL之间传递 

MFC或者由MFC派生的对象的指针的话,我们也必须使用MFC扩展DLL。  



在本节中,我们使用MFC扩展DLL来创建一个输入通用对话框,如图 

13。3所示。该对话框很象Visual  Basic中的InputBox函数所产生的对 

话框,使用过Visual  Basic的程序员都有印象,函数InputBox非常之 

好用,这里,我们来使用动态链接库在Visual   C++ 的MFC中也创建这 

么一个好用的类。  



                               



                 图13。 3 输入通用对话框  



输入通用对话框由类CInputDlg封装,类CInputDlg提供了一个公有成 

员函数GetInput,该成员函数的原型如下:  



CString GetInput(CString Title; CString Prompt)  



第一个参数Title表示输入对话框的标题,在图13。3中为 “输入”; 

第二个参数Prompt代表在输入对话框中显示的简短提示文本,在图 

13。3中为 “请输入对话框的标题:”。函数的返回值为用户在对话框 

的文本框中输入的字符串。如果用户没有输入任何字符串或者单击了 

 “取消”按钮,返回值为空串〃〃。  



下面我们来介绍该对话框的创建和使用。首先讲述DLL工程 

ExtDllDemo的创建。该工程实现了类CInputDlg的导出。  


…………………………………………………………Page 676……………………………………………………………

1。             使用AppWizard创建一个MFC扩展DLL工程,将工程取名为 

ExtDllDemo。  



2。  向工程中添加一个对话框资源IDD_INPUT,按图13。3绘制对话框中 

的各控件。这些控件的资源ID如表所示。  



                   表13。 1 对话框资源IDD_INPUT中的控件属性  



                           控件          资源ID  



                           提示文本        IDC_PROMPT  

                           标签  



                           输入文本        IDC_EDIT  

                           框  



3。         使用ClassWizard为对话框资源IDD_INPUT创建新的对话框类 

CInputDlg,该类直接派生于CDialog。按下面的代码修改类 

CInputDlg的头文件和实现文件。  



#if !defined(AFX_INPUTDLG_H__02DB98CF_1F76_11D2_971A_0000B4810A31__INCLUDED_)  



#define AFX_INPUTDLG_H__02DB98CF_1F76_11D2_971A_0000B4810A31__INCLUDED_  



#if _MSC_VER 》= 1000  



#pragma once  



#endif // _MSC_VER 》= 1000  



// InputDlg。h : 头文件  



//  



// 以下对话框 ID 常量需要手动添加  



#define IDC_EDIT 100

返回目录 上一页 下一页 回到顶部 0 0

你可能喜欢的