《C语言实例教程(PDF格式)》第139章


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
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 系统预安装?
小说推荐
返回首页返回目录