在非MFC工程中使用MFC的库_afxwin在不是mfc的环境下_晒太阳的魚的博客-程序员秘密

技术标签: C++  

原作者:luoweifu https://blog.csdn.net/luoweifu/article/details/41527069


需求说明

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

1fatal 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 <windows.h>

 

 

问题分析

对于第1个问题,很简单:

选中工程名右键属性(Project),在Properties\Configuration Properties\General\Use of MFC中选择Use MFC in a Shared DLL 

出现上面第2个问题主要是因为包含头文件的顺序不对。为什么包含WINDOWS.H的时候会有顺序要求,网上有一段传播的非常广泛解释:

 如果在MFC工程中#include   <windows.h>,那么会有以下编译错误(因为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   <windows.h>         
  如果编译器在编译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 <afxwin.h>的包含语句把到最前面。

sunshine1314 的博文《MFC工程使用MFC库时的问题及解决办法》给出了一序列的解决方案,大家可能参考一下,也许能解决你们的问题。但我当时通过这一系列方法还是没能解决我的问题。

 

我的解决方案

我的问题是:用Firebreath开发浏览器插件,通过fbgen.py和prep2010.cmd脚本帮我们生成了基于VS2010的工程(这个工程中没有stdaf.h),我们要在这个工程中获得MFC中的HDC以及使用MessageBox,于是就碰到了上面提到的问题。

解决方案:

手动添加stdafx.h和stdafx.cpp文件使用预编译机制,在stdafx.h的最前面包含<afxwin.h>。于是问题就变成了stdafx.h的原理和手动添加stdafx.h文件及相应配置。下面我们以Win32 Console Application工程的TextProject为例,演示一下这过程。

1.在VS2010中创建Win32 Console Application工程的TextProject,创建向导会自动生成的stdafx.h和stdafx.cpp,省去了手动添加的过程。如果你的工程没有这两个文件可以手动创建。

2.stdafx.h和stdafx.cpp这两个文件已创建并添加到工程,下面讲讲相关的配制。

2.1选中工程名,右键属性(Properties),在Precompiled Header/Precompiled Header中选择Use(/Yu),Precompiled Header File中填stdafx.h。设置工程编译时使用预编译头文件stdafx.h(在VS中文件名的大小写不敏感,即StdAfx.h和stdafx.h是等价的)。

 

 

2.2选中stdafx.cpp文件,右键属性(Properties),在Precompiled Header/Precompiled Header中选择Create(/Yc), Precompiled Header File中填stdafx.h。这样设置的作用是:每次编译stdafx.cpp文件时创建.pch文件(扩展名pch表示预编译头文件 )。

 

 

3.在stdafx.h的开发包含<afxwin.h>文件:

#include <afxwin.h>

4.这时在我们的main函数中写入下面这句话,就可以弹出一个消息框:

AfxMessageBox(L“非MFC工程使用MFC库”, MB_OK, 0 );

Stdafx.h的原理

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/huiyanfei/article/details/80884577

智能推荐

添加自定义对象到GLOBAL Object Services(GOS)_IT小弟的博客-程序员秘密

转载:http://blog.chinaunix.net/uid-15016030-id-21724.html

Android 音乐APP(五)音乐通知栏、后台播放音乐_移动音乐app 带后台_初学者-Study的博客-程序员秘密

Android 音乐通知栏前言正文① 通知栏按钮点击监听② 通知栏点击监听③ 通知栏业务处理④ 运行效果图结语前言  这篇文章的标题有些言简意赅了,也突出了这篇文章的核心,那就是通知栏的操作,你可以看到世面上的音乐类APP都会有这个操作,通过音乐通知栏可以播放暂停、上一曲、下一曲、收藏、显示歌词等等。当然我这个Demo目前不考虑这么多,先实现播放暂停、上一曲、下一曲这些基本功能再说,你说对吧。正文  在第四篇文章的到最后显示了通知栏,那么为什么我要把通知的的操作单独放到一篇文章来进行讲解呢?因为里面

离散数学期末复习总结_做梦好啊的博客-程序员秘密

第一章 命题逻辑基本概念1.1 命题与联结词1.1.1 命题与真值基本概念命题: 判断结果惟一的陈述句不确定真假的陈述句也是命题,只要保证结果唯一陈述句中的悖论也不是命题1.1.2 命题符号化原子命题(简单命题):一个命题不能再分解为更简单的命题复合命题:由简单命题与联结词按一定规则复合而成的命题1.1.3 复合命题及联结词否定式与否定联结词 合取式与合取联结词 “∧”相当于“与”关系满足交换律和结合律析取式与析取联结词 “∨”相当于“或”关系满足交换

diffy,一款使开发和测试从测试中解脱的工具 (一、背景及简介)_舟行于无涯之海的博客-程序员秘密

背景测试,是软件开发的一个十分重要的环节,是软件质量的保证.几乎没有一个产品团队敢向用户/客户交付未经测试的代码.测试虽然只是一个验证阶段,但要完成所有用例的测试,却是一个费时费力的过程.一个项目,从第一个版本发布,到形成一个相对完善的版本,再到后面的重大更新甚至重构,需要经过许多版本的迭代.随着项目的迭代,产品功能不断增加,项目会变得越来 越复杂.然而在后期,我们修改增加的功能相对上一版本已...

[开源]基于goapp+xterm实现webssh-网页上的SSH终端linux管理工具(golang)_? annie? 的博客-程序员秘密

简析基于goapp+xterm实现webssh-网页上的SSH终端,linux管理工具。开源地址见文末。特性在网页上实现一个SSH终端。从而无需Xshell之类的模拟终端工具进行SSH连接。可以对交互命令进行审计、记录在页面上按一个键,就能打开一个webssh,并且自动登录 ,方便地管理各个服务器可以集成到自有的后台管理体系中下载并运行下载可执行文件体验...

kinect笔记 六、简单的虚拟换衣_普通网友的博客-程序员秘密

显示  1、新建一个空对象,命名为KinectController,在此对象上绑定KinectManager、KinectGestures、OverlayController  2、将KinectManager上的ComputeColorMap和UseMultiSourceReader勾选上  3、设置Main Camera(这里的摄像头作为一个Foreground Came...

随便推点

windows下安装web.py快速指南(py3版本安装出错的原因)_strivinging的博客-程序员秘密

环境介绍首先介绍下安装使用的环境 - Windows 7 - Python 3.6Web.py介绍web.py是Python在Web领域一个轻量级的解决方案,所谓轻量,就是非常简单快速满足Web页面开发的需求。 首先来感受一下其轻量的程度吧:import weburls = ( '/(.*)', 'hello')class hello:

pip3 install -r requirements.txt_MartianCoder的博客-程序员秘密

pip3 install -r requirements.txtnumpyopencv…一键配置即可完成!

经典c语言笔试题_fmoonstar的博客-程序员秘密

***********************************************************************************************************************************                             编程区:                     《《《《冒泡排序,二分查找

WOW外挂编写教程---进阶版_3.35外挂_netack的博客-程序员秘密

WOW外挂编写教程---进阶版前一贴入门篇主要写的是感性知识,哪怕没接触过程序设计的人,只要用金山游侠,CE(cheat engine)之类的软件就可以将贴内提到的内容实践一下。但是仅仅了解这些远远不够。正如有人回贴说用按键精灵就可以轻松的实现仿键盘输入功能。而接下来遇到的最大问题就是该输入什么,在什么时候输入,如何知道游戏内人物的状态以及周围的情况。上贴教了一个查找游戏内容的方法,通过不停的改变

简单记录fortran入门过程_基于fortran语言的参数化设计学习步骤_maray的博客-程序员秘密

寒假给堂弟讲C语言。我自然是轻车熟路,但他对C却是一无所知。不用说函数啊,格式啊,变量了,就连void都会写成viod,不知int为何物。各种格式也是一团乱麻。读者切不可笑,今天初次接触fortran,抄了个例子,却一样是编译不过,错误百出。究其原因,对fortran一无所知而已。正好,借此机会好好回忆总结下,如何学习语言。 step 1. 搜索fortran入门,找到 http://mi

全面解读WM_NOTIFY & 消息反射_worldy的博客-程序员秘密

原文:http://blog.csdn.net/hustli/category/12732.aspx 摘要:控件通知消息有很多种,但是有一种是很常用,但是又不是很容易掌握的,那就是WM_NOTIFY,我试着对此做一下比较全面的论述,有不对的地方,还希望各路大虾批评指正。控件通知消息在《深度解析VC中的消息(上)》中,我们提到了消息的分类有3种:窗口消息、命令消息和控件通知消