友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
喜书网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

C语言实例教程(PDF格式)-第104章

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






2000 。reloc  



17000 。text  



由上面的结果得知,msgbox。dll中仅包括了一个导出函数MsgBox()。  



   l 注意:  



   l 仅仅知道导出函数的名称并不足以从DLL 中导出该函数。若在应用 

     程序中使用显式链接 (link explicitly),至少还应该知道导出 

     函数的返回值的类型以及所传递给导出函数的参数的个数、顺序 

     和类型;若使用隐含链接 (link implicitly),必须有包括导出 

     函数 (或类)的定义的头文件 (。H文件)和引入库 (import  

     library,。LIB文件),这些文件是由DLL的创建者所提供的。关 

     于显式链接和隐含链接,将在本章的 “13。2。2 链接应用程序到 

     DLL”小节中讲述。  



从DLL中导出函数有两种方法:  



   l 在创建DLL时使用模块定义 (module DEFinition,。DEF)文件。  


…………………………………………………………Page 666……………………………………………………………

  l 在定义函数时使用关键字__declspec(dllexport)。  



下面我们通过一个简单的例子来分别说明两种方法的使用。在这个例 

子中,我们将创建一个只包括一个函数MsgBox() 的DLL,函数MsgBox 

()用来显示一个消息框,它和Win32   API函数MessageBox()的功能是 

一样,只不过在函数MsgBox()中,不需要指定消息的父窗口,而且可 

以缺省其它所有的参数。  



   (1) 使用模块定义文件  



模块定义文件是一个文本文件,它包括了一系列的模块语句,这些语 

句用来描述DLL的各种属性,典型的,模块语句定义了DLL中所导出的 

函数的名称和顺序值。  



在讲解模块定义文件之前,我们先创建一个Win32                   Dynamic…Link  

Library工程。  



1。 在Microsoft Developer Studio中选择File菜单下的New命令,在 

Projects选项卡中选择Win32 Dynamic…Link Library,并为工程取一 

个名字,如msgbox。单击OK后,Visual  C++创建一个Win32  DLL的空 

白工程,必须手动的将所需要的文件添加到工程中。  



2。  单击Project菜单下的Add  To  Project子菜单下的New命令,在 

Files选项卡中选择Text   File,在File文本框中输入DEF文件名,如 

msgbox。def。  



3。   双击Workspace窗口的FileView选项卡中的msgbox。def节点,在 

msgbox。def文件中输入下面的内容:  



LIBRARY MSGBOX  



DESCRIPTION 〃一个DLL的简单例子〃  



EXPORTS  



MsgBox @1  



在DEF文件中的第一条语句必须是LIBRARY语句,该语句表明该DEF文 

件属于一个DLL,在LIBRARY之后是DLL的名称,这个名称在链接时将 

放到DLL的引入库中。  



EXPORTS语句下列出了DLL的所有导出函数以及它们的顺序值。函数的 

顺序值不是必须的,在指定导出函数的顺序值时,我们在函数名后跟 


…………………………………………………………Page 667……………………………………………………………

上一个@符号和一个数字,该数字即导出函数的顺序值。如果在DEF中 

指定了顺序值,它必须不小于1,且不大于DLL中所有导出函数的数 

目。  



DESCRIPTION语句是可选的,它简单的说明了DLL的用途。  



4。  下一步是向工程中添加一个头文件,它定义了DLL中的函数的返回 

值的类型和参数的个数、顺序和类型。  



单击菜单项Project|Add To Project|New。。。,在Files选项卡下选择 

C/C++   Header   File,在File文本框中指定头文件名,如msgbox。h 

 (可以省略后缀名。h)。  



在头文件中输入如下的内容:  



#include   



extern 〃C〃 int MsgBox(  



// 消息框的文本  



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



// 消息框的标题  



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



// 消息框的样式  



UINT uType=MB_OK);  



请注意函数定义前的关键字extern   〃C〃,这是由于我们使用了C++语 

言来开发DLL,为了使C语言模块能够访问该导出函数,我们应该使用 

C链接来代替C++链接。否则,C++编译器将使用C++的类型安全命名和 

调用协议,这在使用C调用该函数时就会遇上问题。在本例中并不需 

要考虑到这个问题,因为我们在开发DLL和应用程序时都是使用C++, 

但我们仍然强烈建议使用extern   〃C〃,以保证在使用C编写的程序调 

用该DLL的导出函数不会遇上麻烦,在本章后面的内容中我们还会讨 

论到这个问题。  



5。  下面要做的事是向工程中添加一个C++源文件,在该文件中实现函 

数MsgBox()。  



仿照上面的过程,单击菜单项Project|Add  To  Project|New。。。,在 

Files选项卡下选择C++  Source  File,在File文本框中指定源文件 


…………………………………………………………Page 668……………………………………………………………

名,如msgbox。cpp。  



在msgbox。cpp文件中添加如下的代码:  



#include 〃test1。h〃  



int MsgBox(LPCTSTR lpText;  



LPCTSTR lpCaption;  



UINT uType)  



{  



return MessageBox(NULL;lpText;lpCaption;uType);  



}  



编译该工程,在Debug 目录下生成文件msgbox。lib和msgbox。dll。  



在 “13。2。2  链接应用程序到DLL”小节中将讲述如何使用在本节中所 

创建的DLL:msgbox。dll。  



     (2) 使用关键字__declspec(dllexport)  



从DLL中导出文件的另一种方法是在定义函数时使用__declspec 

(dllexport)关键字。这种方法不需要使用DEF文件。  



仍使用前面的例子,在工程中删除msgbox。def文件,将msgbox。h文件 

修改如下:  



#include   



extern 〃C〃 __declspec(dllexport) int MsgBox(  



// 消息框的文本  



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



// 消息框的标题  



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



// 消息框的样式  



UINT uType=MB_OK);  



msgbox。cpp文件并不需要做任何修改,重新编译该工程,在Debug 目 


…………………………………………………………Page 669……………………………………………………………

录下仍生成两个文件msgbox。lib和msgbox。dll。  



在下一小节 “13。2。2  链接应用程序到DLL”中讲述了如何在应用程序 

中使用所创建的DLL:msgbox。dll的导出函数MsgBox()。  



使用__declspec(dllexport)从DLL中导出类的语法如下:  



class __declspec(dllexport) CDemoClass  



{  



。。。  



}  



    



  l 注意:  



  l 如果在使用__declspec(dllexport)的同时指定了调用协议关键 

    字,则必须将__declspec(dllexport)关键字放在调用协议关键字 

    的左边。如:  



  l int __declspec(dllexport) __cdacl MyFunc();  



  l 在32位版本的Visual C++中,__declspec(dllexport)和 

   __declspec(dllimport)代替了16版本中使用的__export关键字。 

    因此,在将16位的DLL源代码移植到Win32平台时,需要把每一处 

   __export替换为__declsped(dllexport)。  



如何从这两种导出函数的方法中作出选择,可以从下面的几个方面考 

虑:  



  l 如果需要使用导出顺序值 (export ordinal value),那么应该 

   使用DEF文件来导出函数。只在使用DEF文件导出函数才能指定导 

    出函数的顺序值。使用顺序值的一个好处是当向DLL中添加新的函 

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

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

   __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   



返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!