分类: C/C++
2010-04-21 20:09:54
DLL(动态链接库)专 题
0.
Windows API中所有的函数都包含在dll中, 其中有3个最重要的DLL。
(1) Kernel32.dll
它包含那些用于管理内存、进程和线程的函数,例如CreateThread函 数;
(2) User32.dll
它包含那些用于执行用户界面任务(如窗口的创建和消息的传送)的 函数,例如CreateWindow函数;
(3) GDI32.dll
它包含那些用于画图和显示文本的函数。
1. 静态库和动态库
(1) 静态库
函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。 在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.Exe文 件).当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库。
(2) 动态库
在使用动态库的时候,往往提供两个文件:一个引入库(.lib)文 件和一个DLL(.dll)文件。虽然引入库的后缀名也是”lib”, 但是动态库的引入库文件和静态库文件有着本质上的区别,对一个DLL来说,其引入库文件(.lib)包 含该DLL导出的函数和变量的符号名,而.dll文 件包含该DLL实际的函数和数据。在使用动态库的情况下,在编译链接可执行文件时,只需要链接该DLL的 引入库文件,该DLL中的函数代码和数据并不复制到可执行文件中,直到可执行程序运行时,才去加载 所需的DLL,将该DLL映射到进程的地址 空间外,然后访问DLL中导出的函数。这时,发布产品时,除了发布可执行文件以外,同时还要发布该 程序将要调用的动态链接库。
2. 在导出库头文件中的标准写法:
#ifdef LIBDAQ_EXPORTS
#define LIBDAQ_API __declspec(dllexport)
#else
#define LIBDAQ_API __declspec(dllimport)
#endif
将该头文件添加到某客户代码中时,会自动展开。如果客户代码没有定义LIBDAQ_EXPORTS, 那么LIBDAQ_EXPORTS会被定义为__declspec(dllimport)表 示有LIBDAQ_EXPORTS头的函数都是从该DLL中 导入的。
3. 名字改编和”extern “C””
C++编译器在生成DLL时,会 对导出的函数进行名字改编,并且不同的编译器使用的改变规则不一样,因此改编后的名字会不一样。这样,如果利用不同的编译器分别生成DLL和 访问该DLL的客户端代码程序的话,后者在访问该DLL的 导出函数时会出现问题。为了实现通用性,需要加上限定符:extern “C”。
但是利用限定符extern “C”可以解决C++和C之 间相互调用时函数命名的问题,但是这种方法有一个缺陷,就是不能用于导出一个类的成员函数,只能用于导出全局函数。
4. 显示加载方式加载DLL
使用动态方式来加载动态链接库时,需要用到LoadLibrary函 数。该函数的作用就是将指定的可执行模块映射到调用进程的地址空间。调用原型为:
HMODULE LoadLibrary(LPCTSTR lpFileName);
LoadLibrary函数不仅可以加载DLL, 还可以加载可执行模块(Exe)。当加载可执行模块时,主要是为了访问该模块内的一些资源,例如对 话框资源、位图资源或图标资源等。LoadLibrary函数有一个字符串类型(LPCTSTR)的 参数,该参数指定了可执行模块的名称,既可以是一个dll文件,也可以是一个exe文 件。如果调用成功,LoadLibrary函数将返回所加载的那个模块的句柄。返回类型HMODULE和HINSTANCE可 以通用。
当加载到动态链接库模块的句柄后,接下来就要想办法获取该动态链接库中导出函数的地址,这可以通过调用GetProcAddress函 数来实现。该函数用来获取DLL导出函数的地址,其原型声明如下所示:
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
参数hModule:指定动态链接库模块的句柄,即LoadLibrary函 数的返回值。
参数lpProcName:一个指向常量的字符指针,指定DLL导 出函数的名字或函数的序号。如果是序号,则序号必须在低位字节中,高位字节必须是0。
如果调用成功,GetProcAddress函数将返回指定导出函数的地址;否 则返回NULL。
例如:
HINSTANCE hInst;
hInst = LoadLibrary(“DllTest.dll”);
typedef int (*ADDPROC)(int a, int b);
ADDPROC add = (ADDPROC)GetProcAddress(hInst, “add”);
if (!add)
print(“Failure”);
else
process next events
FreeLibrary(hInst);
调用语法:
BOOL FreeLibrary(HMODULE hModule);
5. 加载DLL的 两种方式优缺点:
采用动态加载方式,那么可以在需要时才加载DLL,而隐式链接方 式实现起来比较简单,在编写客户端代码时就可以把链接工作做好,在程序中可以随时调用DLL导出的 函数。但是如果程序需要访问十多个DLL时,如果都采用隐式链接方式加载它们的话,那么在该程序启 动时,这些DLL都需要被加载到内存中,并映射到调用进程的地址空间,这样将加大程序的启动时间。 而且一般来说,在程序运行过程中只是在某个条件满足时才需要访问某个DLL中的某个函数,其它情况 下都不需要访问这些DLL中的函数。但是这时所有的DLL都 已经被加载到内存中,资源浪费是比较严重的。这个时候就需要采用显示加载的方式来访问DLL,在需 要时才加载所需的DLL。也就是说在需要时才被加载到内存中,并被映射到调用进程的地址控件中。需 要说明的是,隐式链接方式访问DLL时,在程序启动时也是通过LoadLibrary函 数加载该进程需要的动态链接库的。
6. DllMain函 数
如果提供了DllMain函数(该 函数是可以选择存在的),那么在此函数中不要进行太复杂的调用。因为在加载该动态链接库时,可能还 有一些核心动态链接库没有被加载。例如Use32.dll或GDI32.dll。 我们自己编写的DLL会比较靠前地被加载。
chulia200020012010-04-22 23:39:15
虚函数---为什么gcc和vc编译器的大小不一样 http://topic.csdn.net/u/20100308/14/25862946-e04c-472c-8de7-1325f27df6d6.html 原创 cygwin跨平台移植 gcc+vc联合使用的方法和注意事项 收藏 http://blog.csdn.net/gugu1313/archive/2010/03/28/5425805.aspx
chulia200020012010-04-21 23:45:21
Windows底下gcc以及Qt的DLL文件调用之总结 问题引出:有个微机测控的课程实验,要写个监测温度和湿度的程序。要求通过调用传感设备厂商提供的.DLL库,.LIB库和.h头文件,用MFC写个用户界面。问道:我想用其他的GUI来开发可不可以?老师:不行,因为提供的库是只能用在MFC 里面的。。。我其实是想问,是不是要求必须用MFC,结果老师的回答真让人觉得。。。还有这回事?这里的肯定也可以用在别的GUI开发程序里面,这些东西本质上都是C++库啊。我是想用Qt来开发,开发出来效果肯定很炫的了。。 分析下头文件,只是相关结构体和函数声明,类似于int WINAPI ltm_com_open(int port, int baud, int rtsdtr);就是很普通的Win32函数,感觉用在Qt里面应该没问题。用VC开发只需要把该头文件和.lib库文件添加到工程里面。如何用VC或者 DEV-C++或者Qt生成DLL和LIB的问题就不说了,关于.DLL和.lib 文件的关系简要说明如下: DLL与LIB的区别 : 1.DLL是一个完整程序,其已经经过链接,即
chulia200020012010-04-21 20:51:04
gcc g++ 怎样调用vc的 .lib库文件 http://topic.csdn.net/t/20020904/09/994403.html gcc g++ 的库文件是以.a形式提供的.vc的库文件是以.lib形式提供的。 现想在gcc g++ 中调用.vc的库文件,有什么方法。 4 楼stidio_zhougang(回头是岸)回复于 2002-09-04 11:39:24 得分 50 哈哈,总算让我给搞出来了! 我又查了一些资料,但上面都没有讲这个问题,我想Microsoft提供给人家的API库都是以LIB形式存在的,因此不可能存在着源代码再编译,因此我想了一个变通的方法——— 将MINGW下的lib/winapi/libuser32.a libkernel32.a libgdi32.a这三个文件删除,然后搜索VC 中的user32.lib kernel32.lib gid32.lib三个文件改成上面三个我删除的文件,编译了一个实现多线程图形显示的WIN32工程(《深入浅出MFC》中的第一章的一
chulia200020012010-04-21 20:47:09
GCC能调用vc生成DLL动态连接库吗? http://zhidao.baidu.com/question/11161697.html 我用GCC写程序,想调用自己用VC写的一个*.DLL,不知道怎么写,请大侠们知道一下,GCC也能DLL文件吗? 请说说具体方法,与语法!! 最佳答案 GCC是一个编译器 和DLL调用有啥关系? 你可以在你的代码中显式调用该DLL中的函数 函数 比如函数模型为aaa bbb(ccc ddd); 调用如下: typedef aaa (PROC)(ccc); HINSTANCE hInstance; PROC *pFunction; hInstance=::LoadLibrary("......."); pFunction=(PROC*)::GetProcAddress(hInstance,"bbb"); bbb(...);
chulia200020012010-04-21 20:43:59
如何用VC调用gcc的库
http://zhidao.baidu.com/question/113320678.html
gcc生成的静态库有相关文件.a和.o,生成的动态库有相关文件.o和.dll。
请问如果只有库的.h .a .o .dll文件,那么如何在VC6中调用这些函数。VC6中调用dll用到的.lib文件又应该如何获得?
(最好附一段示例代码)
最佳答案
只要有DLL和头文件就行了,但是需要动态调用。
lib文件是静态调用时所需的,由于各个编译器生成的lib文件可能存在格式上的差异,所以最好是不用.LIB。如果你确实要用,但是又没有对应的.LIB文件,你可以用DLL2LIB转,但是效果不敢保证。最可靠的还是这个DLL的提供者给你提供lib。
付动态调用的一段例子,来自MSDN:
#include