正文

第十八课:动态链接库2007-09-26 19:03:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lym51/29685.html

分享到:

第十八课:动态链接库

一、概念:

1、  静态链接库:

应用程序从函数库中得到所的函数的执行代码,然后把招生代码自身的执行文件中,应用程序在运行时,不再需要函数库的支持。

2、  动态链接库:

应用程序的中不包含函数库中的函数的执行代码,编译和连接时只是包含包含它们的参考,运行时再将它们的执行代码加入内存,所以在程序运行时需要函数的支持。

二、编写DLL

建立一个Windows Dynamic-Link Library,选择建一个An Empty Dll Project,加入一个CPP文件,

int add(int x,int y)

{

return x+y;

}

extern "C" _declspec (dllexport) int add3(int x,int y,int z)

{

        return add(x,y)+z;

}

说明:

1.  Add是一个供DLL中其它函数调用的函数, Add3DLL提供给其它应用程序调用的函数。

2.  DLL中含有输出函数时,编译DLL时会生成DLL文件和LIB文件。LIB文件称为DLL的导入库,它是一个特殊的库文件。它不包含执行代码,只是用来提供给链接器关于DLL函数在DLL中的入口信息,从而使得可执行程序 中也不会包含所调用DLL函数 的代码 ,只保留对DLL函数的动态链接参考。

3.  导出函数的两种方法:

a.  使用微软专用的_declspec (dllexport)(如上面的例子)

cpp文件在编译为OBJ文件时要对函数进行重新命名,C语言会把函数name重新命名为_name,C++会重新命名为_name@@decoration

extern "C"表示用C语言的格式将函数重命名。

b.  使用模块定义文件:

模块定义文件即DEF文件,是包含一个或多个模块定义语句的文本文件,用来描述动态链接库的各种属性。

一个最小的·DEF文件包括以下模块定义语句:

l         第一条语句必须是LIBRARY语句,用来说明动态链接库的名字。

l         EXPORTS语句之后列出动态链接库要输出的函数。用户可以在每个要输出的函数指定一个输出序列号,这只要在对应的函数名之后 加上@符号心腹一个数字即可。注意:这个数字应该是从1到输出函数总数之间的没有重复的数字。指定函数的序列号后,动态加载该函数时,就会通过序列号而不是函数名来检索该函数,因此处理速度将会加快,战胜的内存会减少,从而增加动态链接时的效率。

将上面的例子改为用DEF文件输出:

int add(int x,int y)

{

     return x+y;

}

extern "C"  int add3(int x,int y,int z)

{

        return add(x,y)+z;

}

在工程中加入一文本文件,其名字为dll.def,加入以下语句:

     LIBRARY       dll

EXPORTS

       add3              @    1

三、访问动态链接库:

新建一个基于对话框的MFC工程,

1.  静态调用:

通过编译器提供给应用程序关于DLL的名称,以及DLL函数的链接参考。这种方式不需要在程序中用代码将DLL加载到内存。

a.  DLLLIB文件拷贝到工程目录下,最好在工程的DEBUG目录下也拷贝一份。

b.  ProjectàSettingsàLink中的Object/Library Modules:填入LIB文件的名字。本例中是dll.lib

c.  在对话框中加入一个按钮控件,添加它的响应函数OnButton1(),在其中加入调用代码:

       CString str;

       str.Format("%d",add3(3,4,5));

       MessageBox(str);

d.  加入函数声明:

l         _declspec (dllexport)导出函数的DLL

extern "C"_declspec (dllimport) int add3(int x,int y,int z);

l         DEF文件导出函数的DLL

int add3(int x,int y,int z);

2.  动态调用:

在程序中用语句显式地加载DLL,编译器不需要知道任何关于DLL的信息。

a.  DLL文件拷贝到工程目录下,最好在工程的DEBUG目录下也拷贝一份。

b.  在对话框中加入一个按钮控件,添加它的响应函数OnButton1(),在其中加入调用代码:

CString str;

typedef int (*PADD3)(int x,int y,int z);     

                //定义一种新的数据类型指向函数的指针

PADD3 add3;

HINSTANCE hDll=LoadLibrary("dll");

                //将动态链接库加载到内存

add3=(PADD3)GetProcAddress(hDll,"add3");

               //得到DLL中指定函数的指针

str.Format("%d",add3(3,4,5));

MessageBox(str);

FreeLibrary(hDll);//释放应用程序对DLL的控制权

              说明:如果DLLDEF文件导出函数时为其指定了序列号,比如1,则

                            add3=(PADD3)GetProcAddress(hDll,"add3");

                       可以改为:

                add3=(PADD3)GetProcAddress(hDll, MAKEINTRESOURCE(1));

四、其它:

1.  Windows如何定位DLL

不论是静态调用还是动态调用DLLWindows会按以下顺序寻找DLL

a.  当前路径

b.  Windowssystem路径。用API函数GetSystemDirectory可以得到;

c.  Windows路径。用API函数GetWindowsDirectory可以得到;

d.  环境变量PATH所指定 的路径。

2.  DLL也可以有一个入口函数DllMain(),当然也可以没有。如果有,DllMain会在进程加载、进程缷载、线程加载和线程缷载DLL时自动调用。

3.  为了用户使用方便,应该将导出函数的声明放在一个头文件中。可以使用预处理命令简化更换__declspec(dllexport)__declspec(dllimport)的操作。这样,DLL和应用程序 可以使用相同的头文件:

#ifdef DLL_EXPORTS

#define DLL_API __declspec(dllexport)

#else

#define DLL_API __declspec(dllimport)

#endif

阅读(4888) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册