返回介绍

非 MFC 工程中使用 MFC 库

发布于 2025-02-16 22:59:30 字数 4665 浏览 0 评论 0 收藏 0

需求说明

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 的库就需要包含相应的头文件,经常会遇到下面这个问题:

  1. 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]
  2. 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>
  • 这时在我们的 main 函数中写入下面这句话,就可以弹出一个消息框: AfxMessageBox(L"非 MFC 工程使用 MFC 库", MB_OK, 0 );

Stdafx.h 的原理

关于 stdafx.h 的原理请看下一篇文章 《预编译头文件 (stdafx.h) 的原理》

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文