<a href="http://blog.csdn.net/luoweifu/article/details/41527069#t0">需求說明</a>
<a href="http://blog.csdn.net/luoweifu/article/details/41527069#t1">常見問題</a>
<a href="http://blog.csdn.net/luoweifu/article/details/41527069#t2">問題分析</a>
<a href="http://blog.csdn.net/luoweifu/article/details/41527069#t3">參考解決方法</a>
<a href="http://blog.csdn.net/luoweifu/article/details/41527069#t4">我的解決方案</a>
<a href="http://blog.csdn.net/luoweifu/article/details/41527069#t5">Stdafxh的原理</a>
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 <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>的包含語句把到最前面。
我的問題是:用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 );