天天看點

非MFC工程中使用MFC庫 需求說明 常見問題 問題分析 參考解決方法 我的解決方案 Stdafx.h的原理

<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 &lt;windows.h&gt;

對于第1個問題,很簡單:

選中工程名右鍵屬性(Project),在Properties\Configuration Properties\General\Use of MFC中選擇Use MFC in a Shared DLL 

出現上面第2個問題主要是因為包含頭檔案的順序不對。為什麼包含WINDOWS.H的時候會有順序要求,網上有一段傳播的非常廣泛解釋:

 如果在MFC工程中#include   &lt;windows.h&gt;,那麼會有以下編譯錯誤(因為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   &lt;windows.h&gt;         

  如果編譯器在編譯afxv_w32.h檔案之前編譯了windows.h檔案,編譯器會報上面的錯誤,因為在afxv_w32.h檔案中有下面的一句預編譯報警:   

  #ifdef   _WINDOWS_   

  #error   WINDOWS.H   already   included.     MFC   apps   must   not   #include   &lt;windows.h&gt;   

  #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 &lt;afxwin.h&gt;的包含語句把到最前面。

我的問題是:用Firebreath開發浏覽器插件,通過fbgen.py和prep2010.cmd腳本幫我們生成了基于VS2010的工程(這個工程中沒有stdaf.h),我們要在這個工程中獲得MFC中的HDC以及使用MessageBox,于是就碰到了上面提到的問題。

解決方案:

手動添加stdafx.h和stdafx.cpp檔案使用預編譯機制,在stdafx.h的最前面包含&lt;afxwin.h&gt;。于是問題就變成了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是等價的)。

非MFC工程中使用MFC庫 需求說明 常見問題 問題分析 參考解決方法 我的解決方案 Stdafx.h的原理

2.2選中stdafx.cpp檔案,右鍵屬性(Properties),在Precompiled Header/Precompiled Header中選擇Create(/Yc), Precompiled Header File中填stdafx.h。這樣設定的作用是:每次編譯stdafx.cpp檔案時建立.pch檔案(擴充名pch表示預編譯頭檔案 )。

非MFC工程中使用MFC庫 需求說明 常見問題 問題分析 參考解決方法 我的解決方案 Stdafx.h的原理

3.在stdafx.h的開發包含&lt;afxwin.h&gt;檔案:

#include &lt;afxwin.h&gt;

4.這時在我們的main函數中寫入下面這句話,就可以彈出一個消息框:

AfxMessageBox(L"非MFC工程使用MFC庫", MB_OK, 0 );

繼續閱讀