动态链接库的创建和调用方法

来源:互联网 发布:手机电视投影软件 编辑:程序博客网 时间:2024/05/22 12:12

最近在写dll,看了一些网上的资源,自己整理了一下,这里把它贴出来。好了,进入正题。

    我今天要讲的主要是非mfcdll,也就是win32 dynamic link library ,如下图所示:

                                               

  图   1

1. 一个简单的dll示例

            如图1所示,在file菜单下new一个个Win32 Dynamic-Link Library工程,取名为simple_dll。在建立的工程中添加如下文件

/* 文件名:simple_dll.h */#ifndef SIMPLE_DLL_H#define SIMPLE_DLL_Hextern "C" int _declspec(dllexport)add(int x, int y);#endif/* 文件名:simple_dll.cpp */#include "simple_dll.h"int add(int x, int y){      return x + y;}
如上就建立了一个简单的动态链接库工程。按下F7,或者点击build菜单下的build simple_dll.dll可以在debug文件夹下生成simple_dll.lib和simple_dll.dll文件。

接下来我们编写一个win32 console application工程调用dll中的add函数。在文件菜单下点击新建,new一个win32 console application工程,如下图所示。  名称设为call_simple_dll。
                                               

然后把simple_dll工程中的simple_dll.lib和simple_dll.dll拷贝到call_simple_dll工程目下文件夹下。最后在call_simple_dll下新建main.cpp文件。

/**********文件main.cpp**************/#pragma comment(lib,"simple_dll.lib")#include<stdio.h> //.lib 文件中仅仅是关于其对应DLL 文件中函数的重定位信息extern "C" _declspec(dllimport) add(int x,int y);int main(int argc, char* argv[]){    int result = add(2,3);    printf("%d",result);    return 0;}
调用成功,结果显示为5.

2.  调用dll中的函数

dll中的函数有两种调用方式,静态的和动态的。第1节中的例子属于静态调用。动态调用的方式如下:

按照第1节中的方式建立好工程,及main.cpp。具体代码改成如下:

#include <stdio.h>#include <windows.h>typedef int(*lpAddFun)(int, int); //宏定义函数指针类型int main(int argc, char *argv[]){    HINSTANCE hDll; //DLL 句柄    lpAddFun addFun; //函数指针    hDll = LoadLibrary("..\\Debug\\dllTest.dll");    if (hDll != NULL)   {      addFun = (lpAddFun)GetProcAddress(hDll, "add");      if (addFun != NULL)      {         int result = addFun(2, 3);         printf("%d", result);      }      FreeLibrary(hDll);   }   return 0;}
编译运行,可以得到和第1节中同样的结果。这里我们可以看到所谓动态调用就是使用了LoadLibrary——GetProcAddress——FreeLibrary三个windows API函数。静态调用和动态调用的区别在于,静态调用需要包含lib描述文件。客户端(即main函数)编译连接的时候,会把dll中该函数的地址绑定到main函数。这样,一旦dll发生改变,那么函数的地址也会发生改变。客户端也必须重新编译连接。而动态调用方式,因为使用后期动态绑定,连接的时候不需要知道函数的具体地址。只有在调用的时候,才进行连接。这样,无论dll中的函数怎么修改,反正在客户端调用时会对该函数的地址进行计算,所以即使dll发生改变,也不需要重新编译客户端程序。这就是动态调用和静态调用最主要的区别。当然大家也可以看到,静态调用代码要简洁一些。所以,如果dll功能固定的话,大家可以采用静态链接的方式。

3. dll中函数的导出

可以看到第1节中我们使用

extern "C" int _declspec(dllexport)add(int x, int y);
来声明add函数,这里_declspec(dllexport)的意思就是声明说明(declaration spec)add函数是一个dll导出函数。我们可以把simple_dll.dll用vc6 tools自带的depends工具查看,  如下图,我们可以看到add函数的入口指针为0x00001005 。这样说明将add符号才可以被外界调用。
                                                      
4.dll中变量的导出

变量的导出方式跟函数基本一样

/*文件名: variable.h */#ifndef _VARIABLE_H_#define _VARIABLE_H_#ifdef EXPORT#define VARIABLE_DLL _declspec(dllexport)#else#define VARIABLE_DLL _declspec(dllimport)#endifextern VARIABLE_DLL int dllglobal;#endif/*文件名:variable.cpp */#define EXPORT#include "variable.h"int dllglobal = 33;在主函数中引用DLL 中定义的全局变量:/* 文件名:main.cpp */#include "variable.h"#include<stdio.h>#pragma comment(lib,"variable.lib")int main(){    printf("%d",dllglobal);}  

注意,这里需要将variable.h,variable.lib,variable.dll都拷贝到main.cpp同个文件夹下。否则编译不会成功。


5.dll中类的导出

下面的例子里,我们在DLL 中定义了point 和circle 两个类,并在应用工程中引用了它们。

//文件名:point.h,point 类的声明#ifndef POINT_H#define POINT_H#ifdef   EXPORT#define CLASS_DLL _declspec(dllexport)#else#define CLASS_DLL _declspec(dllimport)#endifclass CLASS_DLL point //导入类point{public:float y;float x;point();point(float x_coordinate, float y_coordinate);};#endif//文件名:point.cpp,point 类的实现#define CLASS_DLL#include "point.h"//类point 的缺省构造函数point::point(){   x = 0.0;   y = 0.0}//类point 的构造函数point::point(float x_coordinate, float y_coordinate){   x = x_coordinate;   y = y_coordinate;}客户端程序#include "circle.h" //包含类声明头文件#pragma comment(lib,"circle.lib");int main(){    circle c;    printf("area:%f girth:%f", c.x, c.y);    return 0;}

0 0
原创粉丝点击