非 MFC 工程中使用 MFC 库
需求说明
C++ 工程的类型有很多,从 VS (或 VC) 可以看到常见的有: Win32 Console Application、MFC Application、Win32 Project 等。在创建 MFC 工程时,通过 IDE 的向导会自动帮我们创建相应的类文件和包含必需的头文件,但有时候我们需要在非 MFC 工程中包含 MFC 的库。至于为什么会有这个需要,为何不在一开始就创建 MFC 工程呢?可能有两种原因:1.在 MFC 工程会产生很多向导生成的代码以及资源文件,如基于单文档的工程会有 View , Doc 等类,很多时候我们并不需要这些东西,只需要一个空工程就可以了。2.使用第三方框架创建的工程,我们很难更改它的工程属性(如用 Firebreath 开发浏览器插件,通过脚本文件 firebreath 会自动帮我们生成 VS 下的工程)。
常见问题
在非 MFC 工程中使用 MFC 的库就需要包含相应的头文件,经常会遇到下面这个问题:
- fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
- fatal error C1189: #error : WINDOWS.H already included. MFC apps must not #include
问题分析
对于第 1 个问题,很简单:
选中工程名右键属性 (Project),在 Properties\Configuration Properties\General\Use of MFC 中选择 Use MFC in a Shared DLL
出现上面第 2 个问题主要是因为包含头文件的顺序不对。为什么包含 WINDOWS.H 的时候会有顺序要求,网上有一段传播的非常广泛解释:
如果在 MFC 工程中#include ,那么会有以下编译错误(因为 afxwin.h 文件中包含了 afx.h,afx.h 文件中包含了 afxver.h,afxver.h 中包含了 afxv_w32.h,而 afxv_w32.h 中包含了 windows.h,请看以下分析):
compile error:
c:\program files\microsoft visual studio\vc98\mfc\include\afxv_w32.h(14) :
fatal error C1189: #error : WINDOWS.H already included. MFC apps must not #include
如果编译器在编译 afxv_w32.h 文件之前编译了 windows.h 文件,编译器会报上面的错误,因为在 afxv_w32.h 文件中有下面的一句预编译报警:
#ifdef _WINDOWS_
#error WINDOWS.H already included. MFC apps must not #include <windows.h>
#endif
问题在于为什么 afxv_w32.h 中要有这么一句预编译处理。看了 afxv_w32.h 和 windows.h 文件就有点明白了。
在 afxv_w32.h 中有下面的预编译语句:
... ...
#undef NOLOGERROR
#undef NOPROFILER
#undef NOMEMMGR
#undef NOLFILEIO
#undef NOOPENFILE
#undef NORESOURCE
#undef NOATOM
... ...
在 afxv_w32.h 中还有一句:
#include "windows.h"
而在 windows.h 文件中有下面的预编译语句:
... ...
#define NOATOM
#define NOGDI
#define NOGDICAPMASKS
#define NOMETAFILE
#define NOMINMAX
#define NOMSG
#define NOOPENFILE
... ...
注意到在 windows.h 的开头有防止 windows.h 被重复编译的预编译开关:
#ifndef _WINDOWS_
#define _WINDOWS_
这样问题就明白了,虽然我不知道微软为什么要这么做,但是我知道如果在 afxv_w32.h 没有那句预编译报警,那么如果在编译 afxv_w32.h 之前编译了 windows.h,那么在 windows.h 中 #define 的 NOATOM 等宏就会被#undef 掉,可能会导致相应的错误发生。
猜想原因可能如上所述,我的解决方法是,将包含有 #include “windows.h" 的头文件放在所有包含的头文件的最后面,这样使得对 afxv_w32 文件
的编译处理发生在先,这样,由于在 afxv_w32.h 中已经包含了 windows.h ,那么宏 WINDOWS 将被定义,后继的 #include "windows.h" 语句将形同虚设,
上面的编译报警也不会发生了。我觉得这种处理要比将所有的 #include "windows.h” 语句删掉要好一点。
一句话,编译器必须在编译 windows.h 之前编译 afxv_w32.h, 因为我不是十分清除什么时候 afxv_w32.h 会被编译,所以我将可能包含有#include "windows.h" 的头文件放在其他头文件之后 #include。
参考解决方法
解决这个问题的总体思路是:把 #include 的包含语句把到最前面。
sunshine1314 的博文《非 MFC 工程使用 MFC 库时的问题及解决办法》给出了一序列的解决方案,大家可能参考一下,也许能解决你们的问题。但我当时通过这一系列方法还是没能解决我的问题。
我的解决方案
我的问题是:用 Firebreath 开发浏览器插件,通过 fbgen.py 和 prep2010.cmd 脚本帮我们生成了基于 VS2010 的工程(这个工程中没有 stdaf.h),我们要在这个工程中获得 MFC 中的 HDC 以及使用 MessageBox ,于是就碰到了上面提到的问题。
解决方案: 手动添加 stdafx.h 和 stdafx.cpp 文件使用预编译机制,在 stdafx.h 的最前面包含 。于是问题就变成了 stdafx.h 的原理和手动添加 stdafx.h 文件及相应配置。下面我们以 Win32 Console Application 工程的 TextProject 为例,演示一下这过程。
- 在 VS2010 中创建 Win32 Console Application 工程的 TextProject,创建向导会自动生成的 stdafx.h 和 stdafx.cpp,省去了手动添加的过程。如果你的工程没有这两个文件可以手动创建。
- stdafx.h 和 stdafx.cpp 这两个文件已创建并添加到工程,下面讲讲相关的配制。
- 选中工程名,右键属性(Properties),在 Precompiled Header/Precompiled Header 中选择 Use(/Yu),Precompiled Header File 中填 stdafx.h。设置工程编译时使用预编译头文件 stdafx.h (在 VS 中文件名的大小写不敏感,即 StdAfx.h 和 stdafx.h 是等价的)。
- 选中 stdafx.cpp 文件,右键属性 (Properties),在 Precompiled Header/Precompiled Header 中选择 Create(/Yc), Precompiled Header File 中填 stdafx.h。这样设置的作用是:每次编译 stdafx.cpp 文件时创建.pch 文件(扩展名 pch 表示预编译头文件 )。
- 在 stdafx.h 的开发包含 文件:
#include <afxwin.h>
在WIN32 DLL中使用MFC
2015年07月13日 18:22:05
阅读数:377
最近用WIN32 DLL,为了方便要用到MFC的一些库,又不想转工程,就网上找了很多方法,发现没有详细的介绍,有的也行不通,现在成功在WIN32 DLL中使用了MFC,记录一下以防以后用到忘记
一、修改预编译头文件(stdafx.h)
在stdafx.h文件中添加下面代码,包含一些MFC的头文件,这些可以在一个MFC工程中复制过来
1 #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将为显式的 2 3 #include <afxwin.h> // MFC 核心组件和标准组件 4 #include <afxext.h> // MFC 扩展 5 6 #ifndef _AFX_NO_OLE_SUPPORT 7 #include <afxole.h> // MFC OLE 类 8 #include <afxodlgs.h> // MFC OLE 对话框类 9 #include <afxdisp.h> // MFC 自动化类 10 #endif // _AFX_NO_OLE_SUPPORT 11 12 #ifndef _AFX_NO_DB_SUPPORT 13 #include <afxdb.h> // MFC ODBC 数据库类 14 #endif // _AFX_NO_DB_SUPPORT 15 16 #ifndef _AFX_NO_DAO_SUPPORT 17 #include <afxdao.h> // MFC DAO 数据库类 18 #endif // _AFX_NO_DAO_SUPPORT 19 20 #include <afxdtctl.h> // MFC 对 Internet Explorer 4 公共控件的支持 21 #ifndef _AFX_NO_AFXCMN_SUPPORT 22 #include <afxcmn.h> // MFC 对 Windows 公共控件的支持 23 #endif // _AFX_NO_AFXCMN_SUPPORT
二、修改编译配置
我使有的是VS2003
1、项目->属性->常规->MFC的使用->在静态库中使用MFC(动态或静态都可以)
2、链接器->输入->
因为编译的时候会因为链接的顺序问题导致链接错误,所以这里要改两个LIB的链接顺序
先在‘忽略指定库中’忽略掉这两个DLL,分别是uafxcw.lib和libcpmt.lib,如果是DEBUG工程,还需要填入libcmt.lib
再在'附加依赖项'中以uafxcw.lib libcpmt.lib的顺序填入
三、在你的主文件中加入代码
在最前面加入
#ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW / // global data // The following symbol used to force inclusion of this module for _USRDLL #ifdef _X86_ extern "C" { int _afxForceUSRDLL; } #else extern "C" { int __afxForceUSRDLL; } #endif
这样不用从CWinApp中派生一个类再外部定义来使用MFC的入口点,可以直接使用原来的写好的DllMain入口点
只是在链接那一块还是出了几个错误,
error LNK2005: "private: __thiscall type_info::type_info。。。
最后用的:
附加依赖项:msvcrtd.lib LIBCMTD.lib
忽略特定库:LIBCMTD.lib;msvcrtd.lib
编译通过了,MFC的类编译器也认识了