参考资料:

https://msdn.microsoft.com/en-us/library/30c674tx.aspx

http://www.cnblogs.com/qrlozte/p/4844429.html

http://www.cnblogs.com/qrlozte/p/4850642.html

在上面给出的MSDN链接中,你可以看到四种DLL的定义。这里就不赘述。捡重点的说

区别就在于:

  • NON-MFC DLL内部不能使用MFC(当然其导出的API也不能涉及MFC)。(这里我说“导出的API”是指导出的C函数、C++类或者共享的全局变量等等)
  • Regular DLL Statically/Dynamically linked to MFC内部可以使用MFC,但是其导出的API不能涉及MFC(比如说涉及到MFC的某个类或其子类,包括你写的MFC的子类,以及任何没有在该DLL中运行的MFC代码;说人话,就是任何涉及MFC的代码都只能在DLL内部运行,如果你从DLL中导出,再由其他的EXE或者DLL运行,是不行的。)当然,根据该DLL是动态链接到MFC库还是静态链接到MFC库又细分成了两种。
  • MFC Extension DLL内部可以使用MFC,并且其导出的API也可以涉及MFC。
  • 可以看到,从NON-MFC DLL到MFC Extension DLL,其可使用的功能越来越多。NON-MFC DLL可以导出C函数,全局变量,普通的C++类,但不能涉及MFC;Regular DLL具备NON-MFC DLL的所有能力,并且其内部可以使用MFC,但不能将涉及MFC的部分导出;MFC Extension DLL具备Regular DLL的所有能力,并且可以导出使用MFC的API。

1、如何在VS中创建四种DLL的项目

1.1、NON-MFC DLL

新建项目>VC++>Win32>Win32项目>选择DLL

1.2、Regular DLL Statically/Dynamically linked to MFC

新建项目>VC++>MFC>MFC DLL>选择Statically linked to MFC / Dynamically linked to MFC

1.3、MFC Extension DLL

新建项目>VC++>MFC>MFC DLL>选择MFC Extension DLL

DLLDEMO项目:

举例说明了NON-MFC DLL(AddXxx.dll):导出了C函数,全局变量,非MFC的C++类。

举例说明了Regular DLL Dynamically linked to MFC(Add.dll):导出了C函数,一个非MFC的C++类,二者都可以在其内部使用MFC创建一个对话框。并且通过InfoDlgFactory说明了为什么Regular DLL不能把MFC类导出。见InfoDlg.cpp中InfoDlgFactory的注释。

举例说明了MFC Extension DLL(AddExt.dll):导出了C函数,MFC子类,该子类是一个对话框。

测试程序:FontView.exe,点击Print Sample按钮可以测试三种DLL,相关代码在CMainWindow::OnPushButtonClicked中可以看到

下载地址:下载DLLDEMO

备注:

1、AFX_MANAGE_STATE的作用

https://msdn.microsoft.com/en-us/library/0asx94f7.aspx

https://msdn.microsoft.com/en-us/library/30c674tx.aspx

简单来说,假设你的项目有一个a.EXE,b.DLL,  c.DLL,a动态链接到b,b动态链接到c,那么实际上a,b,c是三个模块。当代码执行路径(code path)从a到b或者从b到c的时候,涉及到一个“模块状态”的切换,当然这个“模块状态”要掰开揉碎了说就能说上一天也不一定说的完了,总之AFX_MANAGE_STATE就是干这个事的。如果没有它就会出现各种错误。

在编写AddExt.dll的代码的时候,由于没仔细看MSDN中的说明,在InfoDlgFactoryExt中使用了AFX_MANAGE_STATE从而导致了LNK2005错误(error LNK2005: _DllMain@12 already defined in dllmain.obj)。实际上MFC Extension DLL用不着这个,AFX_MANAGE_STATE只是拿给动态链接到MFC的Regular DLL用的(https://msdn.microsoft.com/en-us/library/30c674tx.aspx;“The AFX_MANAGE_STATE macro should not be used in regular DLLs that statically link to MFC or in extension DLLs. ”)。

2、什么地方需要使用AFX_MANAGE_STATE

前提条件,DLL是动态链接到MFC库的regular dll。并且,涉及到模块切换的地方,也就是说只要涉及到一个模块调用实现在另一个模块内的代码,并且这个代码调用了MFC库的代码的时候。就应该使用AFX_MANAGE_STATE。下面举例说明

打开Add项目,查看CInfoDlg和DoModalDlgImpl的定义

class CInfoDlg : public CDialog, public IInfoDlg

查看IInfoDlg的定义就知道,IInfoDlg纯粹是一个interface,里面只有pure virtual函数,作为Add.dll的接口用。CDialog是MFC类。所以CInfoDlg也是MFC类,因此CInfoDlg的创建、使用、销毁都会调用MFC库。

因此IInfoDlg的DoModalDlg和Release以及InfoDlgFactory都会调用MFC库。所以这三个方法都使用了AFX_MANAGE_STATE

class DoModalDlgImpl : public IDoModalDlg

IDoModalDlg也是一个interface,所以DoModalDlgImpl只是一个普通的C++类。其创建、使用和销毁会不会调用MFC库取决于它的实现。

现在去看DoModalDlgImpl的实现。

可以看到只有DoModalDlgImpl::DoModalDlg里面创建了CInfoDlg并且调用了CInfoDlg::DoModal,所以只有DoModalDlgImpl::DoModalDlg会调用MFC库。

因此,可以看到,DoModalDlgImpl相关的DoModalDlg、Release、DoModalDlgFactory,只有DoModalDlg需要使用AFX_MANAGE_STATE。

3、为什么不要直接export一个DLL中的C++类,或者MFC类

http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

一个C++类(MFC类也不例外)包含两个部分,interface和implementation,即接口和实现,public和protected的部分属于interface(protected部分仅仅对子类来说是interface)。

看上面引用的文章“What you see is not what you get”

你把实现在一个DLL中的类导出,目的是导出它的接口,而不是实现。但是,直接用__declspec(dllexport)导出一个C++类不仅把其接口部分给导出,其实现部分也给导出了,所以,假设一个类的实现用到了其他的类(比如说通过继承或者通过成员),这些部分也会被导出,这个过程会一直进行下去,所以这样一来你本来只想导出3个方法,结果导出了万八千个你不想导出的东西。

这就是为什么在DLLDEMO中,接口部分都用的interface(只有pure virtual函数的C++类),这样就解决了这个问题。

四种DLL:NON-MFC DLL, Regular DLL Statically/Dynamically Linked to MFC, MFC Extension DLL的更多相关文章

  1. MFC 在对话框显示图片的多种方法(四种方法)

    我们先从简单的开始吧.先分一个类: (一) 非动态显示图片(即图片先通过资源管理器载入,有一个固定ID) (二) 动态载入图片(即只需要在程序中指定图片的路径即可载入) 为方便说明,我们已经建好一个基 ...

  2. WinDbg常用命令系列---.load, .loadby (Load Extension DLL)

    .load, .loadby (Load Extension DLL) 简介 .load和.loadby命令将新的扩展DLL加载到调试器中. 使用形式 .load DLLName !DLLName.l ...

  3. .Net,Dll扫盲篇,如何在VS中调试已经编译好的dll?

    什么是Dll? DLL 是一个包含可由多个程序同时使用的代码和数据的库. 例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数.因此,每个程序都可以使用该Dll中 ...

  4. 错误 1 无法将程序集“NBear.Data.dll”复制到文件“D:\newbpm\bpm\SureBpm\Bin\NBear.Data.dll”。无法将“D:\newbpm\bpm\SureSoft.WebServiceBaseLib\bin\Debug\NBear.Data.dll”添加到网站。 无法添加文件“Bin\NBear.Data.dll”。 拒绝访问。 D:\..

    错误 1 无法将程序集“NBear.Data.dll”复制到文件“D:\newbpm\bpm\SureBpm\Bin\NBear.Data.dll”.无法将“D:\newbpm\bpm\SureSof ...

  5. Asp.net 面向接口可扩展框架之使用“类型转化基础服务”测试四种Mapper(AutoMapper、EmitMapper、NLiteMapper及TinyMapper)

    Asp.net 面向接口可扩展框架的“类型转化基础服务”是我认为除了“核心容器”之外最为重要的组成部分 但是前面博文一出,争议很多,为此我再写一篇类型转化基础服务和各种Mapper结合的例子,顺便对各 ...

  6. C#播放声音的四种方法 +AxWindowsMediaPlayer的详细用法

    C#播放声音的四种方法 第一种是利用DirectX 1.安装了DirectX SDK(有9个DLL文件).这里我们只用到MicroSoft.DirectX.dll和 Microsoft.Directx ...

  7. 细说Mysql四种安装方法及自动化部署

    一.简介 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库, 每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据. 我们也可以将数据存储在文件中,但是 ...

  8. VBA中四种自动运行的宏以及模块的含义

    在Excel的“标准模块”中可以创建4种自动运行的宏,它们分别是Auto_Open(打开工作 簿时自动运行), Auto_Close, Auto_Activate,  Auto_Deactivate. ...

  9. JDBC驱动的四种类型

    Java中的JDBC驱动可以分为四种类型,包括JDBC-ODBC桥.本地API驱动.网络协议驱动和本地协议驱动. JDBC驱动类型一.JDBC-ODBC桥 JDBC-ODBC 桥 是sun公司提供的, ...

随机推荐

  1. Javascript 笔记与总结(1-6)Javascript 面向对象

    在 JavaScript 中,有对象,没有类(但有构造函数). 在 JavaScript 中,对象不依赖于类而存在,可以直接生成. {key:value, key:value} 这种格式的对象,成为 ...

  2. windows下Gulp安装

    目录: 1.安装nodejs2.使用命令行3.npm介绍4.选装cnpm5.全局安装gulp6.新建package.json文件7.本地安装gulp插件8.新建gulpfile.js文件9.运行gul ...

  3. java 时间戳和PHP时间戳 的转换

    java 时间戳和PHP时间戳 的转换 PHPJava  总结一下java 时间戳和PHP时间戳 的转换问题: 由于精度不同,导致长度不一致,直接转换错误. JAVA时间戳长度是13位,如:12948 ...

  4. Java中的定时调度

    Timer类是一个线程设施,用于实现在某个时间或者某一段时间后安排某个任务执行一次或者定期重复执行.需要与TimerTask配合使用. TimerTask类用来实现由Timer安排的一次或重复执行的某 ...

  5. for循环经典案例

    1.棋盘放粮食棋盘有32个格子,第一个格子放1个芝麻,第二个放2个,第三个放4个,第四个放8个...每个芝麻的重量为0.00001kg,如果要放满整个棋盘,需要多少重量的芝麻. <!DOCTYP ...

  6. 如何查看google chrome 插件源码

    常用浏览器google chrome 有很多优秀的插件,寂寞的时候想看看人家是怎么实现的,说是快那就动手吧 插件代码位置 本人mac笔记本,chrome 插件位置如下 $ cd  /Users/vin ...

  7. linux shell工具集合

    1)判断进程是否存在,如果不存在再执行启动命令,可以避免一个脚本同时启动多份 if [ $(ps -ef |grep  bastion_account.sh|grep -v grep|wc -l) - ...

  8. NHibernate学习笔记

    原文详见http://www.cnblogs.com/GoodHelper/archive/2011/02/16/nhibernate_03.html   NHibernate_Demo程序框架: D ...

  9. NSString的常见方法

    //1.创建常量字符串. NSString *astring = @"This is a String!";   //2.创建空字符串,给予赋值. NSString *astrin ...

  10. freebsd上安装nginx+php记录

    参考文章 https://wiki.freebsdchina.org/faq/ports http://www.vpsee.com/2014/04/install-nginx-php-apc-mysq ...