孙鑫关于DLL(Dynamic Link Library)动态链接库的视频讲座笔记和学习小结

来源:互联网 发布:刘嘉忆 知乎 编辑:程序博客网 时间:2024/04/30 20:00

孙鑫关于DLL(Dynamic Link Library)动态链接库的视频讲座笔记和学习小结

听课时间:2009920

整理日期:2009921

一、使用DLL的优点

①、多种语言编写(Visual Studio 6.0Delphi 2008)

代码提供者可以选择自己熟悉的语言开发DLL功能封装模块

项目工程可以由熟练掌握不同开发环境的工程师参与进来

②、有利于增强产品的功能

功能可以被快速扩展实现,类似于面向对象中的类和派生类的关系

产品可以单独发布像皮肤插件、音效插件等一些日新月异的功能需求

③、为市场提供二次开发平台,有利于产品的推广和应用

用户可以根据自己的产品规划,基于其他功能提供商的DLL,开发新的创新型产品

如,国际OPC基金会提供了opc_aeps.dllopccomn_ps.dllopchda_ps.dllOPCProxy.dllOPC接口规范的相关DLL通用文件,其会员单位又基于这些SDK二次开发出OPCClient.dllOPCServer.dll等商用DLL,一些对OPC接口存在需求的个人或公司无偿或有偿获得二次开发出的DLL,嵌入到自己的产品中,从而为终端用户提供利益服务。

      英国Datapath公司、国内惠州天敏公司、厦门四信公司等,他们的主要产品是硬件,但他们都提供了自己产品的二次开发库,用户可以利用简捷、快速的动态库封装接口,开发出自己的特有产品,不用花费精力去研究自己不熟悉的相关硬件业务处理,大大提升了产品的研发周期。

④、降低编译的复杂性,有利于单元测试,简化了项目管理

DLL单独编译不参与所属工程的编译,大大提升了编译效率,简化了工程工作区的规模,利于软件开发者集中精力解决当前任务。

⑤、节省磁盘空间和内存

      虽然当前计算机技术突发猛进,但作为一名软件开发人都应该时刻保持一种为用户节约资源、提高单位工作效率为目标。一个DLL在内存中仅保存一份实例,提高了系统的内存利用率。

⑥、有助于资源共享

      面对软件技术的不断成熟,软件开发从业者的不断积累,我们应该建立自己的代码库,将通用的、常用的功能封装起来,简化自己的开发工作,努力让自己的DLL被他人所认可和接受。

⑦、用助于实现产品的国际化

可以封装和调用不同的语言包

二、DLL简述

DLL是一种二进制磁盘文件(通常带有.dll扩展名),它由全局数据、导出函数、类和资源组成。

Windows系统中非常重要的DLL有:Kernel32.dll管理内存、进程和线程的各个函数;User32.dll执行用户界面任务的各个函数;GDI32.dll画图和显示的各个函数。

在运行时被系统加载到进程的虚拟空间中,成为调用进程的一部分,如果与其它DLL没有冲突,一般映射到进程虚拟空间的同一地址上。

图一

每个Win32进程都有4G虚拟内存空间,进程不能访问上端2G和下端2G中的64K隔离区,隔离区的目的:防止进程非法访问非授权区域,增强进程的健壮性和安全性。

EXE一般被加载到内存中的地址为:0X40000000DLL一般被加载到内存中的地址为:0X10000000,多个DLL依次分配。

2.2、静态链接库与动态链接库

静态库:函数和数据被编译成一个二进制文件(.LIB),与EXE一起编译产生执行文件,库中的函数和数据被复制到执行文件中

动态库:由一个引入库(.LIB)和一个DLL文件组成。引入库中包含DLL导出函数和变量的符号名,DLL包含实际的实现代码和数据。编译执行文件时,只需引入库即可。

三、dumpbin 应用简述

运行cmd命令,可能提示如下:

图二

你可到Visual Studio 的安装目录下

C:/Program Files/Microsoft Visual Studio/VC98/Bin

中找到 VCVARS32.BAT 将其拖动到命令窗口中,

图三

接着你就可以尽情调用 dumpbin 调试DLL

-exports 导出信息

-imports 导入信息

四、Depends应用简述

开始 程序 Microsoft Visual Studio 6.0

Microsoft Visual Studio 6.0 Tools Depends

图四

?原因:主要系在OPCDCCManager.exe的所在目录中没有找到调用库文件

五、代码编写时的注意事项

①、_declspec(dllimport) 效率比 extern 声明效率更高,建议使用前者,前者明确告诉编译器定义是来自于一个LIB输入库文件

②、DLL头文件中的条件编译指令

#if defined DLL_EXPORT

#define CFGMODULE_API __declspec(dllexport)

#else

#define CFGMODULE_API __declspec(dllimport)

#endif

上述条件编译指令, DLL调用方可以使用,DLL自己也可以使用;此时需要在DLL.cpp文件中,定义 #define DLL_EXPORT 宏,之后包含 #include DLL的导出信息头文件;

对于一个工程来说,头文件不参与编译,.cpp文件单独编译。

③、导出C++

class DLL_EXPORT Point  //导出整个类

{

public:

      void output();

}

④、获取调用DLL方的窗口句柄

GetForegroundWindow

HWND hwnd = GetForegroundWindow();

HDC hdc = GetDC(hwnd);

//……

ReleaseDC(hwnd, hdc);

⑤、名字改编引起的问题

编译器不同,名字改编的规则是不同的;为解决C++C之间的库函数调用,我们可以使用extern "C" ,它的缺点是:不能导出类的成员函数

模块定义文件 .def 用来解决名字改编问题

新建一个.txt文件,把它的名字强制改为 .def文件

在工作区中,选择菜单 Project Add To Project Files,添加上述创建的.def文件,在该文件中定义导出函数

LIBRARY DLLNAME 该名字要和DLL的发布名字一致

EXPORTS

add

subtract

⑥、标准调用约定 _stdcall C调用约定 _cdecl_fastcall调用约定

_stdcall其实就是WinAPIPasical调用约定

dumpbin –exports 时看到的函数名:_add@8,其中的8代表函数的参数字节数,即:_functionname@number.

函数的参数自右向左入栈,被调用函数返回前负责清理传送参数的内存栈。

C调用约定 _cdecl

参数传递与_stdcall一致,但C调用约定规定用于参数传递的内存栈由调用者负责维护(也正因为如此,实现可变参数的函数只能使用该约定)。另外在函数名的修饰方面也有所不同,即_functionname

_fastcall调用约定主要特点就是速度快,它通过寄存器传递参数(实际上,它用ECXEDX传送前两个双字或更小的参数,剩下的参数仍旧自右至左入栈传递,被调用的函数在返回时负责清理传送参数时的内存栈)。在函数名的修饰方面也是独树一帜,即:@functionname@number

名字改编均不改变函数名的大小写。

⑦、DLLMain

创建DLL的一个可选项,在这个函数中不要执行太复杂的应用,因为此时系统的一些核心DLL可能还未被加载。

⑧、应用程序少一个DLL都无法继续运行,LIB起到程序定位表的作用

⑨、MFC扩展DLL只能被MFC应用程序所使用

六、隐式链接和显示链接

通过引入库(LIB)隐式

#include "" //

#pragma comment(lib, "");

应用程序编译时将LIB引入库中的信息引入执行文件中,运行时通过引入库访问DLL的导出函数

Windows搜索应用程序需要的DLL的顺序为:

①、包含应用程序EXE文件的目录

②、进程的当前目录

③、Windows系统目录

④、Windows目录

⑤、列在Path环境变量中的一系列目录

如果隐式链接的DLL过多,会严重影响应用程序的启动时间。

显式

LoadLibraryGetProcAddressFreeLibrary

      用户决定DLL的加载时机。GetProcAddress 中可以使用,MAKEINTERSOURCE(),参数为函数的顺序号,这样调用DLL函数的速度会很快。