DLL基本概念
DLL(Dynamic Linkable Library)可以看作存储直接可用变量、函数、类的仓库。这种仓库的发展经历了“无库->静态链接库->动态链接库”三个阶段。
LIB与DLL
静态链接库和动态链接库都是共享代码的方式。使用静态链接库时,LIB中的指令最终都被包含到生成的exe中。动态链接库可以在工程中动态的引用和卸载。另外静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
DLL与具体编程语言和编译器关
DLL具有约定的接口规范和调用方式,与具体的编程语言和编译器无关,如Windows中生成的DLL可以在任何开发环境中使用。
VC中的DLL
MFC支持规则(Regular)和扩展(Extension)两种类型的DLL。
MFC规则DLL与MFC扩展DLL一样,使用MFC类库编写的,特点是在源文件里面包含一个继承自CWinApp的类,但其无消息循环。规则DLL按照连接方式又分为动态连接(共享版本)和静态连接(独立与MFC库运行)两种。
MFC支持的三种DLL如下(一般推荐第二种方式):
1、使用共享MFC DLL的规则DLL(Regular DLL using shared MFC DLL)
创建:DLL的创建需要MFC的支持时使用。
使用:动态链接MFC类,要求环境中存在MFC。
特点:DLL应用程序从CWinApp派生,但没有消息循环。
2、带静态连接MFC的规则DLL(Regular DLL with MFC statically linked (Client doesn't have to be MFC based))
别称:Non-MFC DLL
创建:推荐使用
使用:DLL可在MFC和非MFC环境中使用。
特点:因为生产时使用的所有类的代码均以编译到DLL中,因此占用空间也增大。
输入函数中包含如下:
extern "C" EXPORT YourExportedFunction( );如果没有extern “C”修饰,输出函数仅仅能从C++代码中调用。
3、MFC扩展DLL(MFC Extension DLL (Using shared MFC DLL))
创建:DLL中包含派生于MFC的类时,构建这种DLL。
使用:使用扩展DLL时,要求环境中必须存在MFC,在项目中选择“在共享DLL中使用MFC”。
特点:扩展DLL访问MFC的类通过连接到MFC的共享版实现,所以使用MFC扩展版时,MFC的共享版必须可用。
DLL编译方法(VS2008)
1、输出DLL的配置
头文件中增加如下定义
#ifdef DLLDIR_EX
#define DLLDIR __declspec(dllexport) // export DLL information
#else
#define DLLDIR __declspec(dllimport) // import DLL information
#endif
#define DLLDIR __declspec(dllexport) // export DLL information
#else
#define DLLDIR __declspec(dllimport) // import DLL information
#endif
VC6.0中,“工程-设置-C/C++-Preprocessor Definition”增加“,DLLDIR_EX”
注:输出宏的命名方式为<projectname>_EXPORTS。
2、DEBUG和RELEASE输出不同名称
以DEBUG版本名称后面加“D”为例:
(1)复制一份*.def文件,名称修改为*D.def,并将文件中LIBRARY对应的名称关键字后加D。
(2)“配置属性”-“连接器”-“常规”-“输出文件”加D,修改为$(OutDir)\$(ProjectName)D.dll;
(3)“配置属性”-“连接器”-“输入”-“模块定义文件”加D,修改为.\*D.def;
(4)重新生成解决方案。
DLL编译常见问题
1、Invalid Address specified to RtlValidateHeap
原因分析:由于不同的模块(工程)之间传递对象,而两个模块使用了不同的运行时库的设置。如EXE 模块调用 DLL 模块里传递 C++ 类的函数,但 DLL 模块使用静态链接(Release 是 Multi-threaded (/MT) 、Debug 是 Multi-threaded Debug (/MTd) )方式编译,而 EXE 模块使用动态链接(Release 是 Multi-threaded DLL (/MD) 、Debug 是 Multi-threaded Debug DLL (/MDd) )方式编译。
解决方法:对比两个模块的工程属性 - C/C++ - Code Generation - Runtime Library,看设置是否一致,修改为一致即可。
2、CDynLinkLibrary 内存泄漏
原因分析:该内存泄漏为误报,MFC 程序加载 MFC DLL(或非 MFC 程序加载了多个 MFC DLL)时,并且这些模块都是共享 MFC 的运行时库(即链接时启用了“Use MFC in a Shared DLL”),但是它们又需要加载不同版本的 MFC 运行时库的情况下,不同版本的 MFC 运行时库分别管理各自的状态,因此造成内存中存在多个 MFC 的状态拷贝,本来这种情况其实是正常的,但调试器会误以为发生了错误。
解决方法:若是自己编译的DLL,尽量保证DLL与项目的字符集一致(均为Unicode或MBCS);若是调用别人的DLL,可以不处理该泄漏,觉得难受可以在模块卸载时输出分隔调试信息以便于将误报与真正的内存泄漏区分出来。
3、HEAP[*.exe]: Invalid Address specified to RtlFreeHeap( 00990000, 00ADE710 )
参考网址:
1、DLL和exe里的malloc和free不能混用:http://hi.baidu.com/huhe/blog/item/0b422edd1f1563d98c1029a3.html
原因分析:一个模块一个堆,一个线程一个栈。dll里malloc的内存,在exe里free会出错。
解决办法:
1、在DLL中输出一个函数给EXE调用,专门用来释放由DLL分配的内存;
2、用GlobalAlloc()代替new,用GlobalFree()代替delete;
3、使用单一的堆,分配内存使用HeapAlloc(GetProcessHeap(),0,size),释放内存使用HeapFree(GetProcessHeap(),0,p);
4、修改开发环境设置:把dll和exe的Settings的C/C++选项卡的Code Generation的Use Run-time library改成Debug Multithreaded DLL,在Release版本中改成Multithreaded DLL;这样使用一个CRT了——MSVCRT.DLL。
2、用GlobalAlloc()代替new,用GlobalFree()代替delete;
3、使用单一的堆,分配内存使用HeapAlloc(GetProcessHeap(),0,size),释放内存使用HeapFree(GetProcessHeap(),0,p);
4、修改开发环境设置:把dll和exe的Settings的C/C++选项卡的Code Generation的Use Run-time library改成Debug Multithreaded DLL,在Release版本中改成Multithreaded DLL;这样使用一个CRT了——MSVCRT.DLL。
不同的CRT下申请释放内存函数对照
| C语言 | C++语言 | Windows平台 | COM | IMalloc | BSTR | |
| 申请 | malloc() | new | GlobalAlloc() | CoTaskMemAlloc() | Alloc() | SysAllocString() |
| 重新申请 | realloc() | GlobalReAlloc() | CoTaskRealloc() | Realloc() | SysReAllocString() | |
| 释放 | free() | delete | GlobalFree() | CoTaskMemFree() | Free() | SysFreeString() |
DLL进阶:DLL和EXE之间的内存管理
参考资料:
1、DLL和exe里的malloc和free不能混用的问题:http://bjwf.cndev.org/2004/06/03/559/
重要概念
C运行时库(C Run-time Library)
运行时库是程序在运行时需要的库文件,通常运行时库以lib和dll形式提供。
C运行时库诞生于20世纪70年代,当时应用程序多为单线程的。随着多线程技术的发展,C运行时库无法满足程序的需求。C运行时库使用了多个全局变量(例如errno)和静态变量,这可能在多线程程序中引起冲突。假设两个线程都同时设置errno,其结果是后设置的errno会将先前的覆盖,用户得不到正确的错误信息。
因此,Visual C++提供了两种版本的C运行时库,一种版本供单线程应用程序使用,另一版本供多线程应用程序调用。多线程运行时库与单线程运行时库有两个重大差别:
(2)多线程库中的数据结构以同步机制加以保护,这样可以避免访问时候的冲突。
标准C++库
Visual C++提供的多线程运行时库又分为静态链接库和动态链接库两类,而每一类运行时库又可再分为debug版和release版,因此Visual C++共提供了6个运行时库。如下表:
Visual C++提供的多线程运行时库又分为静态链接库和动态链接库两类,而每一类运行时库又可再分为debug版和release版,因此Visual C++共提供了6个运行时库。如下表:
|
Standard C++ Library
|
Characteristics
|
Option
|
Preprocessor directives
|
|
LIBCP.LIB
|
Single-threaded, static link
|
/ML
|
|
|
LIBCPMT.LIB
|
Multithreaded, static link
|
/MT
|
_MT
|
|
MSVCPRT.LIB
|
Multithreaded, dynamic link (import library for MSVCP71.dll)
|
/MD
|
_MT, _DLL
|
|
LIBCPD.LIB
|
Single-threaded, static link
|
/MLd
|
_DEBUG
|
|
LIBCPMTD.LIB
|
Multithreaded, static link
|
/MTd
|
_DEBUG, _MT
|
|
MSVCPRTD.LIB
|
Multithreaded, dynamic link (import library for MSVCP71D.DLL)
|
/MDd
|
_DEBUG, _MT, _DLL
|
参考资料:
1、Regular DLL Tutor For Beginners【必读】:http://www.codeproject.com/Articles/6351/Regular-DLL-Tutor-For-Beginners
2、C run-time libraries:http://msdn.microsoft.com/en-us/library/abx4dbyh(v=vs.80).aspx
3、Invalid Address specified to RtlValidateHeap:http://blog.youkuaiyun.com/bao_qibiao/article/details/5257150
4、VC++动态链接库(DLL)编程深入浅出【必读】:http://blog.youkuaiyun.com/lee_eric/article/details/1319439
5、DLL(Dynamic Link Libraries)专题【必读】:http://www.microsoft.com/china/community/program/OriginalArticles/techdoc/dll.mspx
6、MFC 加载多个 dll 时 CDynLinkLibrary 内存泄漏:http://blog.sina.com.cn/s/blog_5c9cff0e0100b9aa.html
本文详细介绍了DLL的基本概念、LIB与DLL的区别、VC中DLL的类型(规则DLL、扩展DLL)、DLL的编译方法以及常见问题解决策略。包括如何在VS2008中配置输出DLL的配置、DEBUG和RELEASE输出不同名称的方法、DLL编译常见问题及其解决方法,旨在帮助开发者深入理解DLL的使用与优化。
8579

被折叠的 条评论
为什么被折叠?



