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

来源:互联网 发布:黑魂三男性捏脸数据 编辑:程序博客网 时间:2024/05/18 16:38

这里因为篇幅有限,就不以我项目中的来说了,为了简单理解,就新建个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处理即可!~


说的有点乱,看得懂就行了。



0 0
原创粉丝点击