您的位置:首页 > 其它

VS2005中调用已经在其他程序中编写好的dll文件

2014-12-15 15:36 288 查看
这里因为篇幅有限,就不以我项目中的来说了,为了简单理解,就新建个test.dll文件吧,原理一样,下面开始:

这里可以新建一个测试DLL的工程

在主调函数的外部加入dll中函数的声明



extern int add(int a,int b);

extern int subtract(int a,int b);

这时候编译...

会出现三个错误,都是发生在链接阶段:



这是是因为没有加入dll的原因,因为程序无法找到add和subtract的函数主体,没法调用,搞了我很长时间。

为了解决这个问题可以将目标原先创建的引入库(.lib)文件复制到Dlltest项目所在的目录下,这这文件中就包含了testDll.dll中的导出函数的符号名.



先找到准备移动的引入库文件

复制



引入完成后需要在VS2005工程属性中加入这个testDLL.lib文件,如下:



这时候再次编译的,则会成功的生成test2.exe可执行文件.也就是说,当应用程序需要调用某个动态链接库提供的函数时,在程序链接时只需要包含该动态链接库提供的输入库文件(.lib)就可以了.(函数的引入库.lib没有包含实际的代码,他只是用来为链接程序提供必要的信息,以便在可执行文件中建立动态链接时需要用到的重定位表)

仍然可以通过dumpbin查看可执行(.exe)文件的输入信息以及其加载DLL的信息

dumpbin -imports test2.exe



从图中的输入信息可以看到,test2.exe程序需要调用到的testDll.dll链接库中的两个函数:add和subtract,另外还可以从中看到一些需要用到的其他DLL文件以及其中所需要用到的函数,并不是dll中的所有函数这个文件都会用上

注意:这里是通过复制.lib的方法使程序编译成功的,另外一种方法是可以在VS2005项目属性中设置相应的属性完成对.lib文件的引用,这样就不用复制.lib文件到项目所在目录中了,上图:



然后继续像第一种方法一样在输入中加入testDll.lib即可



再次运行test2.exe程序,但发现程序会弹出如下图所示的错误对话框,提示无法找到testDll.dll文件



这涉及到.dll文件的加载顺序规则问题了,当引用程序运行的时候,系统将为它分配一个4GB的地址空间,然后加载模块会分析该应用程序的输入信息,从中找到该程序要访问动态链接库信息,然后在用户机器上搜索这些动态链接库,进而加载他们.搜索的顺序如下:

1.程序的运行目录,即.exe所在的目录:

例如



即.exe所在的目录

2.当前目录

3.系统目录:

依次是--C:\WINNT\SYSTEM32;C:\WINNT\SYSTEM;C:\WINNT

4.path环境变量中所列出的路径

其实总结起来,就是按照path环境变量来处理.dll的加载规则的

利用_declspec(dllimport)声明外部.dll中的函数

除了使用extern关键字声明函数是外部定义的函数外,还可以使用_declspec(dllimport)来声明函数是从动态链接库中引入的.例如:

_declspec(dllimport) int add(int a,int b);

_declspec(dllimport) int subtract(int a,int b);

然后编译....

一样可以运行,与使用extern关键字这种方式比,使用_declspec(dllimport)声明的外部函数会告诉编译器该函数是从动态链接库中引入的,编译器可以生成运行效率更高的代码.

完善DLL例子

一个dll实现之后通常都会交给客户程序,以便后者能够访问该dll.但是客户端程序如何知道该dll中有哪些导出函数呢?通常在编写动态链接库时都会提供一个头文件,在此文件中提供的dll导出函数原型的声明,以及函数的有关注释文档.这样可以在工程中添加一个头文件testDll.h

内部添加

_declspec(dllimport) int add (int a,int b);

_declspec(dllimport) int subtract(int a,int b);

这里注意testDll.h是给该dll的客户端,即调用该dll的程序使用,就是这里的test2.exe,因此在声明的函数头部使用的是"dllimport"关键字,向客户端程序表明他们是从动态链接库中导入的.

然后在test2工程中加入头文件testDll.h,在程序的头部加入#include"testDll.h"随即可以使用了

这里可以对testDll.h进行改造,使其不仅能够为调用动态链接库的客户端程序服务,同时也能够由动态链接库程序自身来使用:

#ifndef

#define DLL_API _delcspec(dllimport)

#endif

DLL_API int add(int a,int b);

DLL_API int subtract(int a,int b);

接下来,在动态链接库的源程序:testDll.cpp文件中首先利用#define指令定义DLL_API宏,然后在用#include"testDll.h"包含上述的头文件,之后在定义add和subtract函数时就不用再指定_declspec(dllimport)了,如下

#define DLL_API _declspec(dllexport)

#include "testDll.h"

int add(int a,int b);

int subtract(int a,int b);

在程序编译的时候头文件是不参与编译的,源文件单独编译.

从DLL中导出C++类

跟函数情况基本相同,是在class 和类名之间加入导出标识符DLL_API宏,这样就能导出整个类了.

但是像private和protected在外界是无法访问的,只有public能直接访问

#ifndef DLL_API

#define DLL_API _declspec(dllimport)

#else

#define DLL_API _declspec(dllexport)

class DLL_API Point{

public:

void output(int x,int y);

}

而其余的步骤与只包括函数的dll文件是一样的,即把一个class当做一个function处理即可!~

说的有点乱,看得懂就行了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: