码迷,mamicode.com
首页 > 编程语言 > 详细

vc++ DLL开发小结

时间:2015-08-30 17:37:01      阅读:321      评论:0      收藏:0      [点我收藏+]

标签:

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_H

extern 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 dllTest

EXPORTS

dllGlobalVarDATA

使用方法:

#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_FILE

class_declspec(dllexport) point  //导出类point

#else

class_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_FILE

class_declspec(dllexport) circle  //导出类circle

#else

class_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.1415926

circle::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

版权声明:本文为博主原创文章,未经博主允许不得转载。

vc++ DLL开发小结

标签:

原文地址:http://blog.csdn.net/lqlblog/article/details/48105883

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!