多个类封装dll即dll与lib

本文详细介绍了DLL(动态链接库)和LIB(静态链接库)的区别,包括它们的工作原理、用途和优缺点。创建DLL时会生成一个LIB文件,用于在运行时指示系统需要哪个DLL文件。DLL提供了跨语言支持、封装性和版本控制优势。创建DLL的步骤包括定义DllMain函数、使用__declspec(dllexport)导出函数和类,以及通过.def文件导出函数。调用DLL有两种方式:隐式链接和显式链接,各有优缺点。导出类和函数时,推荐使用显式链接以增强安全性。文章还讨论了导出类和导出函数的注意事项,包括内存跟踪和避免未解析外部符号的问题。
摘要由CSDN通过智能技术生成

介绍:

转载:http://www.cnblogs.com/lancidie/archive/2011/03/12/1982253.html

1:神马是Dll和Lib,神马是静态链接和动态链接

大家都懂的,DLL就是动态链接库,LIB是静态链接库。DLL其实就是EXE,只不过没main。

动态链接是相对于静态链接而言的。所谓静态链接就是把函数或过程直接链接到可执行文件中,成为可执行程序中的一部分,当多个程序调用同样的函数时,内存里就会有这个函数的多个拷贝,浪费内存资源。而动态链接则是提供了一个函数的描述信息给可执行文件(并没有内存拷贝),当程序被夹在到内存里开始运行的时候,系统会在底层创建DLL和应用程序之间的连接关系,当执行期间需要调用DLL函数时,系统才会真正根据链接的定位信息去执行DLL中的函数代码。

在WINDOWS32系统底下,每个进程有自己的32位的线性地址空间,若一个DLL被进程使用,则该DLL首先会被调入WIN32系统的全局堆栈,然后通过内存映射文件方式映射到这个DLL的进程地址空间。若一个DLL被多个进程调用,则每个进程都会接收到该DLL的一个映像,而非多份的拷贝。但,在WIN16系统下,每个进程需要拥有自己的一份DLL空间,可以理解为何静态链接没啥区别。

 

2:DLL和LIB区别和联系。

DLL是程序在运行阶段才需要的文件。

LIB是程序编译时需要链接的文件。

DLL只有一种,其中一定是函数和过程的实现。

LIB是有两种。若只生成LIB的话,则这个LIB是静态编译出来的,它内部包含了函数索引以及实现,这个LIB会比较大。若生成DLL的话,则也会生成一个LIB,这个LIB和刚才那个LIB不同,它是只有函数索引,没有实现的,它很小。但是这俩LIB依然遵循上个原则,是在编译时候是需要被链接的。若不链接第一个LIB的话,在程序运行时会无法找到函数实现,当掉。若不链接第二个LIB的话,在程序运行时依然会无法找到函数实现。但第二种LIB有一种替代方式,就是在程序里,使用LoadLibrary,GetProcAddress替代第二个LIB的功能。第一种LIB生成的EXE文件会很大,因为LIB所有信息被静态链接进EXE里了。第二种LIB生成的EXE文件会比较小,因为函数过程实现依旧在DLL内。

(啰嗦了一堆,某志希望大家能够明白两个LIB的区别。要再不行的话,我们可以将静态编译的LIB称为 静态链接库。但动态编译的LIB称为 引入库。可能会比较好一些。)

静态链接LIB的优点是免除挂接动态链接库,缺点是EXE大,版本控制麻烦些。

动态链接DLL的优点是文件小,版本更换时换DLL就好了,缺点是多了点文件。动态链接若是被多个进程使用,会更加方便和节省内存。

 

3:为什么编译DLL时总会同时生成一个LIB?这个LIB有用吗?

若我们不是用静态链接,而使用DLL,那么我们也需要一个LIB,这个LIB的作用是被链接到程序里,在程序运行时告诉系统你需要什么DLL文件。这个LIB里保存的是DLL的名字和输出函数入口的顺序表。它是有意义的。

当然,若我们的应用程序里不链接这个LIB,则可以使用LoadLibrary,GetProcAddress来告诉系统我们在运行时需要怎么着DLL以及其内的函数。

 

4:DLL意义。

1:DLL真正实现了跨语言。各种语言都可以生成DLL,而对系统以及应用程序来说,哪种语言生成的DLL是没有区别的。

2:DLL有足够的封装性,对于版本更新有很大好处。因为DLL是运行期间才会使用,所以,即使DLL内函数实现有变化(只要参数和返回值不发生变化),程序是不需要进行编译的。大大提高了软件开发和维护的效率。

3:DLL被多个进程使用,因为有内存映射机制,无需占用更多内存。

 

5:创建DLL。(注意:某志就不再讲解使用MFC AppWizard[dll] 方式创建DLL了。有兴趣的自己去百度。这里创建DLL只指使用Win32 Dynamic-link Library创建Non-MFC DLL。呃,DLL的三种类型就不解释了,依旧那句话:百度一下你就知道。)

每个应用程序必须有一个main或者winmain函数作为入口,DLL一样,有自己的缺省的入口函数,就是DllMain。函数如下

BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:   // 进程被调用
 case DLL_THREAD_ATTACH:     // 线程被调用
 case DLL_THREAD_DETACH:   // 线程被停止
 case DLL_PROCESS_DETACH:  // 进程被停止
  break;
 }
 return TRUE;
}

一般情况下,我们不需要对这个缺省的入口函数进行什么修改,它就会使动态链接库得到正确的初始化。但是,当我们的DLL需要额外分配内存或者资源的时候,或者,DLL希望对调用自己的进程或线程进行初始化或清除的额外操作时,可以在上述代码case中加一些自己感冒的东东。(懒……不想细写了- -Orz,现在是晚上2点了,明天还一堆的事情)

DLL对于导出类和导出函数没啥不同。只要加上 __declspec( dllexport ) 修饰函数或者类就好了。

但是有查看过DLL代码的人员都会经常见到这么一段代码

#ifdef FK_DLL_EXPORTS

#define FK_DLL __declspec( dllexport )

#else

#define FK_DLL __declspec( dllimport )

#endif

意义很明显,但是,问题是  FK_DLL_EXPORTS 这个宏是应该在哪儿定义呢?在DLL项目内,还是在使用DLL的应用程序内?

这点某志曾迷糊很久,呵呵~其实后来想想,还是蛮明确的。export是导出。import是导入。对于DLL来说,是要导出这些函数给其他应用程序使用的,所以应当定义 FK_DLL_EXPORTS 宏。对于使用DLL的应用程序来说,是导入,是无需定义的。

使用时候也很简单。

class FK_DLL CMyDllClass{} ;

则整个类被导出。

FK_DLL void MyTestFun( int a );

则该函数被导出。

但是有时我们可以见到这样的代码

extern "C" FK_DLL void MyTestFun2( float b );

其中extern "C"的原理就是标示该函数要求以C形式去进行编译,不要以C++形式去编译。具体的编译原理就不罗嗦了,简而言之,被extern "C"定义函数,可以被C以及其他语言进行DLL调用,而未被extern "C"定义的函数,C是无法访问DLL中这个函数的。

 

在VS中开发DLL还有一种方式,使用.def文件。

新建个文本文档,改后缀为FKDll.def,加入到工程里。

FKDll.def里加入以下代码

LIBRARY FKDll

EXPORTS

MyTestFun@1

MyTestFun2@2

就可以了。其中,LIBRARY语句是说明.def文件是属于FKDll这个Dll的。EXPORTS下面是我们需要导出的函数名。后面加的@+数字,是表示导出函数的顺序编号。这样就足够了。(详细的自己百度,好困,zzzZZZ)

 

6:使用DLL

使用DLL有两种方式。显式链接和隐式链接。

隐式链接很容易。直接#progam comment(lib, "FKDll.lib") 就可以。当然,也可以在项目工程->属性->链接库里加上库和路径(相对路径和绝对路径都可以)。

显式链接则麻烦些。在程序中使用LoadLibrary加载DLL,再GetProcAddress获取函数实现,在程序退出之前,调用FreeLibrary来动态释放掉链接库。

‍例如:

void Main()

{

     typedef void (*FKDllFun1)(int a);

    FKDllFun1 pFun1;

    HINSTANCE hDLL  = LoadLibrary("FKDll.dll");   // 若hDll为空则读取Dll失败。

    pFun1 = (pFun1)GetProcAddress(hDll, "MyTestFun1" );   // 从应用程序中的DLL镜像中获取名为 MyTestFun1 的函数指针

    pFun1( 100 );

    FreeLibrary(hDl

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值