DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。而对于DLL的学习,主要知识点摘记如下.
1.kernel32.dll是Windows 9x/Me中非常重要的32位动态链接库文件,属于内核级文件。它控制着系统的内存管理、数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保护区域,使别的程序无法占用这个内存区域。
2.user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。
3.系统文件gdi32.dll是存放在Windows系统文件夹中的重要文件,通常情况下是在安装操作系统过程中自动创建的,对于系统正常运行来说至关重要. 包含的函数用来绘制图像和显示文字。
4.vcvarsall.bat是vs里面自带的文件,作用整体上来说就是配置环境变量、工作目录。可以简单看看里面的批处理命令。就是根据本地电脑的配置再次调用另外一个批处理文件。
然后指定调用相应的工具如:cl.exe 、 link.exe 、lib.exe等,路径都在vs安装目录下面,vc\bin 目录,一看便知道。
在命令行界面执行该文件后,该文件所设置的环境信息只是在当前命令行窗口生效,关闭该窗口并重新打开后,需要重新运行该文件进行环境信息配置.
5.应用程序如果想要访问某个DLL中的函数,那么该函数必须是已经被导出的函数(即加了标识符_declspec(dllexport)).为了查看一个DLL中有哪些导出的函数,可以利用VS的命令行工具Dumpbin来实现.如查看DLL1.DLL文件中的导出函数,可以在命令行界面DLL1.DLL文件目录下运行dumpbin -exports DLL1.dll.
6.Depends.exe 是用来反编译VC程序的工具,可以查看PE模块的导入模块以及导入和导出的函数,以及动态剖析PE模块的依赖性和解析C++的函数名称, 可分析dll和exe所依赖的dll。可以看到dll以及dll的函数,可以查看导入导出函数,挺好用的.可以通过 开始/程序/VS/VSTOOLS/打开DEPENDS,然后通过打开文件查看。
主要功能如下:
该工具得到的是你软件中隐式链接的Dll库,也就是用lib关联的Dll模块,无法显示显式链接的Dll模块,也就是用LoadLibrary函数导入的Dll函数
查看 PE 模块的导入模块
查看 PE 模块的导入和导出函数
动态剖析 PE 模块的模块依赖性
解析 C++ 函数名称
7.__declspec(dllimport),变量的导入。
特别要注意的是用extern 声明所导入的并不是DLL中全局变量本身,而是其地址,应用程序必须通过强制指针转换来使用DLL中的全局变量。
通过__declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是其地址了,笔者建议在一切可能的情况下都使用这种方式.
8.导出成员用_declspec(dllexport),导入用_declspec(dllimport),可以在头文件的声明部分使用这两个修饰符对函数,类,变量,或类成员函数进行修饰,来表示该成员是一个导入成员或导出成员。
有一个小技巧,就是使用宏定义作为开关控制,让dll项目和调用dll的项目(函数,C++类等)公用一个头文件:
1>. dll的代码源文件(cpp文件)中定义一个宏 然后包含头文件
2>. 头文件header.h中这样写
3>. 然后就可以在header.h的需要导出或导入的成员用DLLAPI来修饰
这样,在执行宏替换的时候,在dll的代码源文件编译的时候DLLAPI会被替换位_declspec(dllexport),而在调用方,因为没有定义过DLLAPI,所以会被替换成_declspec(dllimport)。
9..extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。
在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等.而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的.
在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。
但是这种方法只能导出全局函数,不能导出一个类的成员函数。
10.__stdcall是函数调用约定的一种,函数调用约定主要约束了两件事:
11.模块定义 (.def) 文件为链接器提供有关被链接程序的导出、属性及其他方面的信息。生成 DLL 时,.def 文件最有用。由于存在可代替模块定义语句使用的链接器选项,通常不需要 .def 文件。也可以将 __declspec(dllexport) 用作指定导出函数的手段。在链接器阶段可以使用/DEF(指定模块定义文件)链接器选项调用 .def 文件。
如果生成的 .exe 文件没有导出,使用 .def 文件将使输出文件较大并降低加载速度。
13.LoadLibrary()载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源.
HMODULE LoadLibrary( LPCTSTR lpFileName);
lpLibFileName String,指定要载入的动态链接库的名称。采用与CreateProcess函数的lpCommandLine参数指定的同样的搜索顺序
返回值 Long,成功则返回库模块的句柄,零表示失败。会设置GetLastError
BOOL WINAPI DllMain( HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved