vc++ DLL开发小结

来源:互联网 发布:易观大数据峰会 编辑:程序博客网 时间:2024/05/16 17:47

DLL开发总结

概论

       DLL(Dynamic Linkable Library),你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量,函数。

       静态库和动态库都是共享代码的方式,它们的区别请参见我的上一篇博文。

  1. DLL的编制与具体的变成语言及编译器无关

只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以

相互调用,譬如Windows提供的系统DLL,在任何开发环境中都能被调用,不在乎其实VisualBasicsVisual C++还是Delphi。

  1. VC动态链接库的分类

VisualC++支持三种DLL,它们分别是Non-MFCDLL(非MFC动态库)、MFC

Regular DLL(MFC规则的DLL)、MFCExtension DLL(MFC扩展DLL)。

       非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC编写的应用程序所调用;MFC规则DLL包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,她们只能被用MFC类库所编写程序所调用。

 

导出函数

      DLL中导出函数的声明有两种方式:一种是在函数声明中加上__declspec(dllexport),另外一种是采用模块定义(.def)文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。

       ①extern “C” int __declspec(dllexport) add(int x, int y);怎样使用可以参见上一篇博客——静态库与动态库的区别。

②LIBRARY dllTest

EXPORTS

add @1

.def文件的规则为:

       ①LIBRARY语句说明.def文件相应的DLL;

       ②EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数后面加@n,表示要导出函数的序号为n

       ③.def文件中的注释由每个注释行开始处的分号指定,且注释不能与语句同行。

       使用.def文件在使用时,可以这样

       hDll = LoadLibrary(“dllTest.dll”);

if(hDll!= NULL)

addFun = (lpAddFun)GetProcAddress(hDll,MAKEINTRESOURCE(1));

FreeLibrary(hDll);

       其中1为导出函数的序号。

 

导出变量

       DLL定义的全局变量可以被调用进程访问;DLL也可以访问调用进程的全局数据,我们来看看在应用工程中引用DLL中变量的例子。

Lib.h

#ifndef LIB_H#define LIB_Hextern intdllGlobalVar;extern"C" int GetGlobalVar();#endif


lib.cpp

#include"lib.h"#include<windows.h> intdllGlobalVar;BOOL APIENTRYDllMain( HANDLE hModule,                                      DWORD ul_reason_for_call,                                      LPVOID lpReserved                                     ){    switch (ul_reason_for_call)       {       case DLL_PROCESS_ATTACH:              dllGlobalVar = 100;              break;       case DLL_THREAD_ATTACH:          case DLL_THREAD_DETACH:                 case DLL_PROCESS_DETACH:               break;    }    return TRUE;}

.def文件为

 

LIBRARY dllTestEXPORTSdllGlobalVarDATA

使用方法:

#include"stdafx.h"#include<windows.h>#include<stdio.h>#pragmacomment(lib,"dllTest.lib") extern intdllGlobalVar; int main(intargc, char* argv[]){       printf("%d ",GetGlobalVar());        *(int *)dllGlobalVar = 1;       //特别要注意的是这种方法导出的并不是变量本身,而是DLL中导出变量的指针,应用程序必       //须通过强制指针转换来使用             printf("%d ",GetGlobalVar());       return 0;}

如果执行这样的赋值操作:

dllGlobalVar= 1;

其结果是dllGlobalVar指针的内容发生变化,程序中以后再也引用不到这个变量了。所以在应用工程中引用DLL中全局变量的一个更好的方法是:

externint _declspec(dllimport) dllGlobalVar;//用_declspec(dllimport)导入

通过_declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是地址了,所以建议在一切可能的情况下都使用这种方式。

 

四DLL导出类

point.h

#ifndefPOINT_H#definePOINT_H #ifdefDLL_FILEclass_declspec(dllexport) point  //导出类point#elseclass_declspec(dllimport) point  //导入类point#endif{public:       float y;       float x;       point();       point(float x_coordinate,floaty_coordinate );}; #endif

point.cpp

#ifndefDLL_FILE#defineDLL_FILE#endif #include"point.h" ////////////////////////////////////////////////////////////////////////Construction/Destruction////////////////////////////////////////////////////////////////////// point::point(){}point::point(floatx_coordinate,float y_coordinate){       x = x_coordinate;       y = y_coordinate;}

 

circle.h

#ifndefCIRCLE_H#defineCIRCLE_H #include"point.h"      #ifdefDLL_FILEclass_declspec(dllexport) circle  //导出类circle#elseclass_declspec(dllimport) circle  //导入类circle#endif{public:       void SetCentre(const point¢rePoint);       void SetRadius(float r);       float GetGirth();       float GetArea();       circle();private:       float radius;       point centre;};<p>#endif</p>

circle.cpp

#ifndefDLL_FILE#defineDLL_FILE#endif #include"circle.h"#definePI 3.1415926circle::circle(){   centre = point(0,0);   radius = 0;}floatcircle::GetArea(){       return PI*radius*radius;}floatcircle::GetGirth(){    return 2*PI*radius;}voidcircle::SetCentre(const point ¢rePoint){       centre = centrePoint;}voidcircle::SetRadius(float r){       radius = r;}

 

调用:

dllCall.cpp

#include"stdafx.h"#include<windows.h>#include"..\circle.h" #pragmacomment(lib,"dllTest.lib"); intmain(int argc, char* argv[]){       circle c;       point p(2.0,2.0);       c.SetCentre(p);       c.SetRadius(1.0);       printf("area:%fgirth:%f",c.GetArea(),c.GetGirth());              return 0;}

 

从上述源代码可以看出,由于在DLL的类实现代码中定义了宏DLL_FILE,故在DLL的实现中所包含的类声明实际上为

Class_declspec(dllexport) point{…….};

class_declspec(dllexport) circle{…………..};

而在应用工程dllCall.cpp中没有定义DLL_FILE,故其包含point.h和circle.h后引入的类声明为:

Class_declspec(dllimport) point{……….};


class_declspec(dllimport) circle{……….};

我们往往通过在类的声明头文件中用一个宏来决定使其编译为class_declspec(dllexport) class_name还是class_declspec(dllimport) class_name版本,这样就不需要两个头文件。

讨论静态库和动态库区别的博客链接

http://blog.csdn.net/lqlblog/article/details/48086569

1 0
原创粉丝点击