TRACE宏對(duì)于VC下程序調(diào)試來(lái)說(shuō)是很有用的東西,有著類似printf的功能;該宏僅僅在程序的DEBUG版本中出現(xiàn),當(dāng)RELEASE的時(shí)候該宏就完全消失了,從而幫助你調(diào)試也在RELEASE的時(shí)候減少代碼量。
使用非常簡(jiǎn)單,格式如下:
TRACE("DDDDDDDDDDD");
TRACE("wewe%d",333);
同樣還存在TRACE0,TRACE1,TRACE2。。。分別對(duì)應(yīng)0,1,2。。個(gè)參數(shù)
TRACE信息輸出到VC IDE環(huán)境的輸出窗口(該窗口是你編譯項(xiàng)目出錯(cuò)提示的那個(gè)窗口),但僅限于你在VC中運(yùn)行你的DEBUG版本的程序。
TRACE信息還可以使用DEBUGVIEW來(lái)捕獲到。這種情況下,你不能在VC的IDE環(huán)境中運(yùn)行你的程序,而將BUILD好的DEBUG版本的程序單獨(dú)運(yùn)行,這個(gè)時(shí)候可以在DEBUGVIEW的窗口看到DEBUGVIE格式的輸出了。
VC中TRACE的用法有以下四種:
1:
TRACE ,就是不帶動(dòng)態(tài)參數(shù)輸出字符串, 類似C的printf("輸出字符串");
2:
TRACE 中的字符串可以帶一個(gè)參數(shù)輸出 , 類似C的printf("...%d",變量);
3:
TRACE 可以帶兩個(gè)參數(shù)輸出,類似C的printf("...%d...%f",變量1,變量2);
4:
TRACE 可以帶三個(gè)參數(shù)輸出,類似C的printf("...%d,%d,%d",變量1,變量2,變量3);
TRACE 宏有點(diǎn)象我們以前在C語(yǔ)言中用的Printf函數(shù),使程序在運(yùn)行過(guò)程中輸出一些調(diào)試信息,使我們能了解程序的一些狀態(tài)。但有一點(diǎn)不同的是:
TRACE 宏只有在調(diào)試狀態(tài)下才有所輸出,而以前用的Printf 函數(shù)在任何情況下都有輸出。和Printf 函數(shù)一樣,TRACE函數(shù)可以接受多個(gè)參數(shù)如:
int x = 1;
int y = 16;
float z = 32.0;
TRACE( "This is a TRACE statement\n" );
TRACE( "The value of x is %d\n", x );
TRACE( "x = %d and y = %d\n", x, y );
TRACE( "x = %d and y = %x and z = %f\n", x, y, z );
要注意的是TRACE宏只對(duì)Debug 版本的工程產(chǎn)生作用,在Release 版本的工程中,TRACE宏將被忽略。
這個(gè)問(wèn)題在論壇中的出現(xiàn)頻率很高。在解決這個(gè)問(wèn)題時(shí),首先要明確Windows處理用戶輸入的方法完全不同于Dos操作系統(tǒng)。當(dāng)用戶按鍵后,Dos應(yīng)用向操作系統(tǒng)提出請(qǐng)求,而在Windows中,當(dāng)用戶事件發(fā)生時(shí),是由Windows請(qǐng)求調(diào)用相應(yīng)的代碼,代碼實(shí)現(xiàn)自己必須的處理,最后將控制返回到操作系統(tǒng)。
當(dāng)你從Dos操作系統(tǒng)編程轉(zhuǎn)向Windows的時(shí)候,你會(huì)很不習(xí)慣Windows的面向事件與消息的處理模式,但是面向?qū)ο蟮奶幚矸椒ㄔ赪indows中非常靈活實(shí)用。
本文要討論的問(wèn)題是如何在應(yīng)用程序中實(shí)現(xiàn)用戶事件的輪詢。例如,當(dāng)你的應(yīng)用程序在忙碌狀態(tài)時(shí),如何探測(cè)用戶按鍵(Escape)來(lái)終止正在進(jìn)行的處理或操作。
當(dāng)用戶按鍵或移動(dòng)鼠標(biāo)導(dǎo)致系統(tǒng)事件發(fā)生時(shí),操作系統(tǒng)將這些事件存儲(chǔ)在相應(yīng)的應(yīng)用程序消息隊(duì)列中,事件會(huì)一直以消息的形式存儲(chǔ)在消息隊(duì)列中直到應(yīng)用程序完消息并將控制返回到Windows,這時(shí)Windows將把消息隊(duì)列中的下一條消息發(fā)送到應(yīng)用程序。
所以,為了確定是否用戶已經(jīng)按下了某一個(gè)按鍵,應(yīng)用程序需要確定某一按鍵的消息當(dāng)前是否在消息隊(duì)列中。為此可以調(diào)用PeekMessage函數(shù),例如:
MSG msg;
// 檢查是否按下 Escape 鍵
if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST,
WM_KEYLAST, PM_REMOVE)) {
if (msg.message == WM_KEYDOWN && msg.wParam
== VK_ESCAPE)
// 退出循環(huán)或者停止處理;
}
第一個(gè)參數(shù)MSG結(jié)構(gòu)接收與消息有關(guān)的信息。第二個(gè)參數(shù)是window句柄,如果程序是基于MFC的應(yīng)用,這個(gè)參數(shù)傳遞m_hWnd即可。下兩個(gè)參數(shù)是確定類型的消息,PeekMessage將返回消息隊(duì)列中落在這兩個(gè)值之間的第一個(gè)消息。因?yàn)檫@里我們感興趣的是按鍵,所以就用WM_KEYFIRST 和 WM_KEYLAST作為參數(shù)。最后一個(gè)參數(shù)可以是PM_NOREMOVE 或者 PM_REMOVE,表示消息信息是否應(yīng)該從消息隊(duì)列中刪除。
如果PeekMessage在請(qǐng)求范圍內(nèi)尋找消息,他返回非零值。這樣上面的代碼檢查是否發(fā)現(xiàn)WM_KEYDOWN消息并且wParam等于VK_ESCAPE,如果發(fā)現(xiàn)則退出循環(huán)并終止代碼的處理。
摘 要偽隨機(jī)數(shù)在計(jì)算機(jī)軟件設(shè)計(jì)中有很廣泛的用途。本文介紹了基于數(shù)學(xué)方法的利用計(jì)算機(jī)產(chǎn)生偽隨機(jī)數(shù)的一種方法,即線性同余法,任何偽隨機(jī)數(shù)的產(chǎn)生都是運(yùn)用遞推的原理來(lái)生成的。
以及在Visual C++環(huán)境中產(chǎn)生偽隨機(jī)數(shù)的兩個(gè)重要函數(shù),rand和srand函數(shù),正確地使用這兩個(gè)函數(shù)是產(chǎn)生性能良好的偽隨機(jī)數(shù)的關(guān)鍵,最后介紹了利用偽隨機(jī)數(shù)生成技術(shù)在MFC中生成基于C/S模式應(yīng)用程序的隨機(jī)校驗(yàn)碼以及利用一種軟件工具ImagePassword產(chǎn)生隨機(jī)密碼。
關(guān)鍵詞偽隨機(jī)數(shù)生成;線性同余法;Visual C++;隨機(jī)校驗(yàn)碼
為追求真正的隨機(jī)序列,人們?cè)捎煤芏喾N原始的物理方法用于生成一定范圍內(nèi)滿足精度(位數(shù))的均勻分布序列,其缺點(diǎn)在于:速度慢、效率低、需占用大量存儲(chǔ)空間且不可重現(xiàn)等。為滿足計(jì)算機(jī)模擬研究的需求,人們轉(zhuǎn)而研究用算法生成模擬各種概率分布的偽隨機(jī)序列。偽隨機(jī)數(shù)是指用數(shù)學(xué)遞推公式所產(chǎn)生的隨機(jī)數(shù)。從實(shí)用的角度看,獲取這種數(shù)的最簡(jiǎn)單和最自然的方法是利用計(jì)算機(jī)語(yǔ)言的函數(shù)庫(kù)提供的隨機(jī)數(shù)發(fā)生器。典型情況下,它會(huì)輸出一個(gè)均勻分布在0和1區(qū)間內(nèi)的偽隨機(jī)變量的值。其中應(yīng)用的最為廣泛、研究最徹底的一個(gè)算法即線性同余法。
線性同余法LCG(Linear Congruence Generator)
選取足夠大的正整數(shù)M和任意自然數(shù)n0,a,b,由遞推公式:
ni+1=(af(ni)+b)mod M i=0,1,…,M-1
生成的數(shù)值序列稱為是同余序列。當(dāng)函數(shù)f(n)為線性函數(shù)時(shí),即得到線性同余序列:
ni+1=(a*ni+b)mod M i=0,1,…,M-1
以下是線性同余法生成偽隨機(jī)數(shù)的偽代碼:
Random(n,m,seed,a,b)
{
r0 = seed;
for (i = 1;i<=n;i++)
ri = (a*ri-1 + b) mod m
}
其中種子參數(shù)seed可以任意選擇,常常將它設(shè)為計(jì)算機(jī)當(dāng)前的日期或者時(shí)間;m是一個(gè)較大數(shù),可以把它取為2w,w是計(jì)算機(jī)的字長(zhǎng);a可以是0.01w和0.99w之間的任何整數(shù)。
應(yīng)用遞推公式產(chǎn)生均勻分布隨機(jī)數(shù)時(shí),式中參數(shù)n0,a,b,M的選取十分重要。
例如,選取M=10,a=b =n0=7,生成的隨機(jī)序列為{6,9,0,7,6,9,……},周期為4。
取M=16,a=5,b =3,n0=7,生成的隨機(jī)序列為{6,1,8,11,10,5,12,15,14,9,0,3,2,13,4,7,6,1……},周期為16。
取M=8,a=5,b =1,n0=1,生成的隨機(jī)序列為{6,7,4,5,2,3,0,1,6,7……},周期為8。
Visual C++中偽隨機(jī)數(shù)生成機(jī)制 用VC產(chǎn)生隨機(jī)數(shù)有兩個(gè)函數(shù),分別為rand(void)和srand(seed)。rand()產(chǎn)生的隨機(jī)整數(shù)是在0~RAND_MAX之間平均分布的,RAND_MAX是一個(gè)常量(定義為:#define RAND_MAX 0x7fff)。它是short型數(shù)據(jù)的最大值,如果要產(chǎn)生一個(gè)浮點(diǎn)型的隨機(jī)數(shù),可以將rand()/1000.0,這樣就得到一個(gè)0~32.767之間平均分布的隨機(jī)浮點(diǎn)數(shù)。如果要使得范圍大一點(diǎn),那么可以通過(guò)產(chǎn)生幾個(gè)隨機(jī)數(shù)的線性組合來(lái)實(shí)現(xiàn)任意范圍內(nèi)的平均分布的隨機(jī)數(shù)。
其用法是先調(diào)用srand函數(shù),如
srand( (unsigned)time( NULL ) )
這樣可以使得每次產(chǎn)生的隨機(jī)數(shù)序列不同。如果計(jì)算偽隨機(jī)序列的初始數(shù)值(稱為種子)相同,則計(jì)算出來(lái)的偽隨機(jī)序列就是完全相同的。要解決這個(gè)問(wèn)題,需要在每次產(chǎn)生隨機(jī)序列前,先指定不同的種子,這樣計(jì)算出來(lái)的隨機(jī)序列就不會(huì)完全相同了。以time函數(shù)值(即當(dāng)前時(shí)間)作為種子數(shù),因?yàn)閮纱握{(diào)用rand函數(shù)的時(shí)間通常是不同的,這樣就可以保證隨機(jī)性了。也可以使用srand函數(shù)來(lái)人為指定種子數(shù)。
分析以下兩個(gè)程序段,
程序段1:
//包含頭文件
void main() {
int count=0;
for (int i=0;i<10;i++){
srand((unsigned)time(NULL));
count++;
cout<<"No"<
程序段1中由于將srand()函數(shù)放在循環(huán)體內(nèi),而程序執(zhí)行的CPU時(shí)間較快,調(diào)用time函數(shù)獲取的時(shí)間精度卻較低(55ms),這樣循環(huán)體內(nèi)每次產(chǎn)生隨機(jī)數(shù)用到的種子數(shù)都是一樣的,因此產(chǎn)生的隨機(jī)數(shù)也是一樣的。而程序段2中第1次產(chǎn)生的隨機(jī)數(shù)要用到隨機(jī)種子,以后的每次產(chǎn)生隨機(jī)數(shù)都是利用遞推關(guān)系得到的。
基于MFC的隨機(jī)校驗(yàn)碼生成
Web應(yīng)用程序中經(jīng)常要利用到隨機(jī)校驗(yàn)碼,校驗(yàn)碼的主要作用是防止黑客利用工具軟件在線破譯用戶登錄密碼,校驗(yàn)碼、用戶名、密碼三者配合組成了進(jìn)入Web應(yīng)用系統(tǒng)的鑰匙。在利用VC開(kāi)發(fā)的基于客戶機(jī)/瀏覽器(Client/Server)模式的應(yīng)用軟件系統(tǒng)中,為了防止非法用戶入侵系統(tǒng),通常也要運(yùn)用隨機(jī)校驗(yàn)碼生成技術(shù)。
本實(shí)現(xiàn)要用到以上介紹到的偽隨機(jī)數(shù)生成技術(shù)。校驗(yàn)碼數(shù)據(jù)將以16進(jìn)制碼方式顯示。主要代碼如下:
void CRandompasswordDlg::OnCreatekey() {
int RanCheckNum = 0;
char out[25]={0};
char keytemp[5]={0};
memset(out,0x30,18);
srand((unsigned)timeGetTime());//產(chǎn)生隨機(jī)數(shù)種子
for(int i=0;i<6;i++){
RanCheckNum = rand();//產(chǎn)生隨機(jī)數(shù)
_itoa(RanCheckNum,keytemp,16);//將隨機(jī)數(shù)轉(zhuǎn)換成16進(jìn)制
memcpy(&out[i*4],keytemp,strlen(keytemp));
}
out[24]=0x00;
strcpy(m_key.GetBuffer(18),out);
UpdateData(FALSE);
}
運(yùn)行結(jié)果如圖1所示:

圖1 利用偽隨機(jī)數(shù)生成隨機(jī)校驗(yàn)碼
程序運(yùn)行時(shí),由于每一次點(diǎn)擊"產(chǎn)生隨機(jī)校驗(yàn)碼"的系統(tǒng)時(shí)間不同,生成隨機(jī)數(shù)的種子就不一樣,因此產(chǎn)生的隨機(jī)數(shù)也是不一樣的,從而保證了校驗(yàn)碼生成的隨機(jī)性。
利用ImagePassword工具產(chǎn)生隨機(jī)密碼
ImagePassword提供一個(gè)可選擇的圖形陣列,通過(guò)隨機(jī)改變圖形陣列中的陣點(diǎn)圖形來(lái)產(chǎn)生隨機(jī)密碼。當(dāng)隨機(jī)點(diǎn)擊圖象陣列中的圖象陣點(diǎn),該陣點(diǎn)中的圖象發(fā)生變化。其運(yùn)行界面如圖2所示:

圖2 ImagePassword運(yùn)行界面
點(diǎn)擊OK按鈕后所產(chǎn)生的隨機(jī)密碼如圖3所示:

圖3 ImagePassword運(yùn)行結(jié)果
ImagePassword產(chǎn)生的密碼的隨機(jī)性依賴于用戶對(duì)圖象陣列中陣點(diǎn)圖象的隨機(jī)選擇,一般來(lái)說(shuō)用戶在圖象陣列中隨機(jī)點(diǎn)擊鼠標(biāo)的次數(shù)越多,最后產(chǎn)生的密碼的隨機(jī)性越強(qiáng)。
結(jié)束語(yǔ)
偽隨機(jī)數(shù)在不同的軟件系統(tǒng)中都得到了很廣泛的應(yīng)用,如何選擇隨機(jī)數(shù)生成種子使得生成的偽隨機(jī)數(shù)性能更佳是軟件設(shè)計(jì)者追求的目標(biāo)之一。本文提到了利用系統(tǒng)時(shí)間作為種子參數(shù)在一定條件下可以滿足軟件的隨機(jī)性需要。利用所產(chǎn)生的隨機(jī)數(shù)在游戲編程,如撲克類游戲中的隨機(jī)發(fā)牌,俄羅斯方塊的隨機(jī)生成等等其他應(yīng)用中都起到很重要的作用。
預(yù)編譯頭文件(precompiled header)
今天在寫(xiě)程序的時(shí)候,突然發(fā)現(xiàn)要測(cè)試的代碼是用c寫(xiě)的,還是用gcc編譯的,可是我已經(jīng)建立了測(cè)試的相關(guān)環(huán)境,沒(méi)辦法,只能一步步的改了,將相關(guān)的頭文件、結(jié)構(gòu)和變量移植以后,編譯了一下(只編譯了C文件),竟然出錯(cuò),出錯(cuò)信息為:fatal error C1010: unexpected end of file while looking for precompiled header directive
然后無(wú)論怎么改代碼都是這一句出錯(cuò)信息,最后改成了一個(gè)最簡(jiǎn)單的空函數(shù),仍然不行,改成cpp文件,然后前面加上#include "stdafx.h",編譯通過(guò),再改成c文件,還是出錯(cuò),然后郁悶了半天,后來(lái)想到是編譯器問(wèn)題,改了半天設(shè)置也沒(méi)搞定,最后沒(méi)辦法只好去網(wǎng)上求助了,輸出precompiled header directive,想不到網(wǎng)上那么多的結(jié)果,看了幾篇,輕松搞定,真后悔沒(méi)有早點(diǎn)在網(wǎng)上搜索,浪費(fèi)了不少時(shí)間。。
解決方法:
1、如果發(fā)生錯(cuò)誤的文件是由其他的C代碼文件添加進(jìn)入當(dāng)前工程而引起的,則Alt+F7進(jìn)入當(dāng)前工程的 Settings,選擇C/C++選項(xiàng)卡,從Category組合框中選中Precompiled Headers,選擇Not Using Precompiled headers。確定。
2、在文件開(kāi)頭添加:
#include "stdafx.h"
對(duì)預(yù)編譯頭文件說(shuō)明如下:
所謂頭文件預(yù)編譯,就是把一個(gè)工程(Project)中使用的一些MFC標(biāo)準(zhǔn)頭文件(如Windows.H、Afxwin.H)預(yù)先編譯,以后該工程編譯時(shí),不再編譯這部分頭文件,僅僅使用預(yù)編譯的結(jié)果。這樣可以加快編譯速度,節(jié)省時(shí)間。
預(yù)編譯頭文件通過(guò)編譯stdafx.cpp生成,以工程名命名,由于預(yù)編譯的頭文件的后綴是“pch”,所以編譯結(jié)果文件是projectname.pch。
編譯器通過(guò)一個(gè)頭文件stdafx.h來(lái)使用預(yù)編譯頭文件。stdafx.h這個(gè)頭文件名是可以在project的編譯設(shè)置里指定的。編譯器認(rèn)為,所有在指令#include "stdafx.h"前的代碼都是預(yù)編譯的,它跳過(guò)#include "stdafx. h"指令,使用projectname.pch編譯這條指令之后的所有代碼。
因此,所有的CPP實(shí)現(xiàn)文件第一條語(yǔ)句都是:#include "stdafx.h"。
------------------------------------
unexpected end of file while looking for precompiled header directive Error executing cl.exe.我在文件頭上添加了:
#include "stdafx.h" 還是不能運(yùn)行,請(qǐng)多指教!
Alt+F7進(jìn)入當(dāng)前工程的Settings,選擇C/C++選項(xiàng)卡,從Category組合框中選中Precompiled Headers,選擇Not Using Precompiled headers。確定。
如果發(fā)生錯(cuò)誤的文件原本是該工程中的,則檢查該文件頭部有沒(méi)有#i nclude "stdafx.h"語(yǔ)句,沒(méi)有的話添加。
如果還不行,也有可能是定義的類或結(jié)構(gòu)體等最后忘了加分號(hào),注意一下
------------------------------------------
問(wèn)題:我在編譯程序中老出現(xiàn)“fatal error C1010: unexpected end of file while looking for precompiled header directive”這一句,但我查看了程序并沒(méi)有錯(cuò),請(qǐng)問(wèn)這是怎么一回事?
A回答:
肯定是一個(gè)新添加的類的.cpp文件開(kāi)頭沒(méi)包含stdafx.h,在該文件最前面加上即可。
BOBO的意見(jiàn):
有時(shí)可以使用右鍵點(diǎn)擊項(xiàng)目工程中的該cpp文件,選擇setting,在c/c++欄,選擇PreCompiled headers,然后設(shè)置第一選項(xiàng),選擇不使用預(yù)編譯頭,解決這個(gè)問(wèn)題。
---------------------------------------
編譯出現(xiàn)問(wèn)題:unexpected end of file while looking for precompiled header directive
解決方案:
需要在文件頭上添加一句:
#include "stdafx.h"
這個(gè)文件定義了源程序?yàn)镃++格式。
否則文件需要保存為.C格式
--------------------------------
錯(cuò)誤:fatal error C1083: Cannot open precompiled header file: 'Debug\test4.pch': No such file or directory
解決方案:
或rebuild all,或重新編譯一下stdafx.cpp就OK了,呵呵,又長(zhǎng)知識(shí)了。
---------------------------------
今天在改一個(gè)很大的程序,慢慢看,慢慢改。突然發(fā)現(xiàn)一個(gè).c文件,里面什么也沒(méi)有, 就幾個(gè)頭文件,我一看,我靠,這不是把簡(jiǎn)單的問(wèn)題搞復(fù)雜了嗎,隨手刪掉那個(gè)c文件。 結(jié)果不能編譯了,我靠:
fatal error C1083: Cannot open precompiled header file: \'Debug/v13_3.pch\':
No such file or directory
怎么rebuild all都不行。
上網(wǎng)查了一下,才搞懂了:
----------------總結(jié)------
如果工程很大,頭文件很多,而有幾個(gè)頭文件又是經(jīng)常要用的,那么
1。把這些頭文件全部寫(xiě)到一個(gè)頭文件里面去,比如寫(xiě)到preh.h
2。寫(xiě)一個(gè)preh.c,里面只一句話:#include "preh.h"
3。對(duì)于preh.c,在project setting里面設(shè)置creat precompiled headers,對(duì)于其他.c文件,設(shè)置use precompiled header file
//
哈哈
我試了一下,效果很明顯,不用precompiled header,編譯一次我可以去上個(gè)廁所,用 precompiled header,編譯的時(shí)候,我可以站起來(lái)伸個(gè)懶腰,活動(dòng)活動(dòng)就差不多啦
---------轉(zhuǎn)載的文章----------
預(yù)編譯頭的概念:
所謂的預(yù)編譯頭就是把一個(gè)工程中的那一部分代碼,預(yù)先編譯好放在一個(gè)文件里(通常是以.pch為擴(kuò)展名的),這個(gè)文件就稱為預(yù)編譯頭文件這些預(yù)先編譯好的代碼可以是任何的 C/C++代碼--------甚至是inline的函數(shù),但是必須是穩(wěn)定的,在工程開(kāi)發(fā)的過(guò)程中不會(huì) 被經(jīng)常改變。如果這些代碼被修改,則需要重新編譯生成預(yù)編譯頭文件。注意生成預(yù)編 譯頭文件是很耗時(shí)間的。同時(shí)你得注意預(yù)編譯頭文件通常很大,通常有6-7M大。注意及 時(shí)清理那些沒(méi)有用的預(yù)編譯頭文件。 也許你會(huì)問(wèn):現(xiàn)在的編譯器都有Time stamp的功能,編譯器在編譯整個(gè)工程的時(shí)候,它 只會(huì)編譯那些經(jīng)過(guò)修改的文件,而不會(huì)去編譯那些從上次編譯過(guò),到現(xiàn)在沒(méi)有被修改過(guò)的文件。那么為什么還要預(yù)編譯頭文件呢?答案在這里,我們知道編譯器是以文件為單 位編譯的,一個(gè)文件經(jīng)過(guò)修改后,會(huì)重新編譯整個(gè)文件,當(dāng)然在這個(gè)文件里包含的所有 頭文件中的東西(.eg Macro, Preprocesser )都要重新處理一遍。VC的預(yù)編譯頭文件保存的正是這部分信息,以避免每次都要重新處理這些頭文件。
預(yù)編譯頭的作用:
根據(jù)上文介紹,預(yù)編譯頭文件的作用當(dāng)然就是提高編譯速度了,有了它你沒(méi)有必要每次都編譯那些不需要經(jīng)常改變的代碼,編譯性能當(dāng)然就提高了。
預(yù)編譯頭的使用:
要使用預(yù)編譯頭,我們必須指定一個(gè)頭文件,這個(gè)頭文件包含我們不會(huì)經(jīng)常改變的 代碼和其他的頭文件,然后我們用這個(gè)頭文件來(lái)生成一個(gè)預(yù)編譯頭文件(.pch文件)
想必大家都知道 StdAfx.h這個(gè)文件。很多人都認(rèn)為這是VC提供的一個(gè)“系統(tǒng)級(jí)別”的編譯器帶的一個(gè)頭文件。其實(shí)不是的,這個(gè)文件可以是任何名字的。我們來(lái)考察一個(gè)典型的由AppWizard生成的MFC Dialog Based 程序的預(yù)編譯頭文件。(因?yàn)锳ppWizard 會(huì)為我們指定好如何使用預(yù)編譯頭文件,默認(rèn)的是StdAfx.h,這是VC起的名字)。我們會(huì)發(fā)現(xiàn)這個(gè)頭文件里包含了以下的頭文件:
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#include <afxcmn.h>
這些正是使用MFC的必須包含的頭文件,當(dāng)然我們不太可能在我們的工程中修改這些頭文件的,所以說(shuō)他們是穩(wěn)定的。那么我們?nèi)绾沃付ㄋ鼇?lái)生成預(yù)編譯頭文件。我們知道一個(gè)頭文件是不能編譯的。所以我們還需要一個(gè)cpp文件來(lái)生成.pch 文件。這個(gè)文件默認(rèn)的就是StdAfx.cpp。在這個(gè)文件里只有一句代碼就是:#include “Stdafx.h”。原因是理所當(dāng)然的,我們僅僅是要它能夠編譯而已,也就是說(shuō),要的只是它的.cpp的擴(kuò)展名。我們可以用/Yc編譯開(kāi)關(guān)來(lái)指定StdAfx.cpp來(lái)生成一個(gè).pch文件,通過(guò)/Fp編譯開(kāi)關(guān)來(lái)指定生成的pch文件的名字。打開(kāi)project ->Setting->C/C++ 對(duì)話框,把Category指向Precompiled Header。在左邊的樹(shù)形視圖里選擇整個(gè)工程 Project Options(右下角的那個(gè)白的地方)可以看到 /Fp “debug/PCH.pch”,這就是指定生成的.pch文件的名字,默認(rèn)的通常是 <工程名>.pch(我的示例工程名就是PCH)。
然后,在左邊的樹(shù)形視圖里選擇StdAfx.cpp.//這時(shí)只能選一個(gè)cpp文件!
這時(shí)原來(lái)的Project Option變成了 Source File Option(原來(lái)是工程,現(xiàn)在是一個(gè)文件,當(dāng)然變了)。在這里我們可以看到 /Yc開(kāi)關(guān),/Yc的作用就是指定這個(gè)文件來(lái)創(chuàng)建一個(gè)Pch文件。/Yc后面的文件名是那個(gè)包含了穩(wěn)定代碼的頭文件,一個(gè)工程里只能有一個(gè)文件的可以有YC開(kāi)關(guān)。VC就根據(jù)這個(gè)選項(xiàng)把 StdAfx.cpp編譯成一個(gè)Obj文件和一個(gè)PCH文件 。
然后我們?cè)龠x擇一個(gè)其它的文件來(lái)看看,//其他cpp文件在這里,Precomplier 選擇了 Use Precompiled Header 一項(xiàng),頭文件是我們指定創(chuàng)建PCH 文件的stdafx.h 文件。事實(shí)上,這里是使用工程里的設(shè)置,(如圖1)/Yu”stdafx.h”,這樣我們就設(shè)置好了預(yù)編譯頭文件,也就是說(shuō),我們可以使用預(yù)編譯頭功能了。
以下是注意事項(xiàng):
1):如果使用了/Yu,就是說(shuō)使用了預(yù)編譯,我們?cè)诿總€(gè).cpp文件的最開(kāi)頭,我強(qiáng)調(diào)一遍是最開(kāi)頭,包含你指定產(chǎn)生pch文件的.h文件(默認(rèn)是stdafx.h)不然就會(huì)有問(wèn)題。如果你沒(méi)有包含這個(gè)文件,就告訴你Unexpected file end. 如果你不是在最開(kāi)頭包含的,
你自己試以下就知道了,絕對(duì)有很驚人的效果?..
fatal error C1010: unexpected end of file while looking for precompiled
header directive
Generating Code...
2)如果你把pch文件不小心丟了,編譯的時(shí)候就會(huì)產(chǎn)生很多的不正常的行為。根據(jù)以上的分析,你只要讓編譯器生成一個(gè)pch文件,也就是說(shuō)把 stdafx.cpp(即指定/Yc的那個(gè)cpp文件)從新編譯一遍,當(dāng)然你可以傻傻的 Rebuild All,簡(jiǎn)單一點(diǎn)就是選擇那個(gè)cpp文件,按一下Ctrl + F7就可以了,不然可是很浪費(fèi)時(shí)間的哦。
是新加的類里沒(méi)加入頭文件stdafx.h
方法1:在新增加的類的文件前#include "stdafx.h"
方法2:在project->settings->C\C++ ->project options里的/Yu"stdafx.h" 刪除
1.unexpected end of file while looking for precompiled header directive
A1、右鍵點(diǎn)工程名,選設(shè)置,然后選c/c++屬性頁(yè),再選catagory選單中選 precompiled header ,將選項(xiàng)置成no use 或者autometic
A2、好像是工程中設(shè)置了預(yù)編譯頭文件,但你的程序中事實(shí)上沒(méi)有添加這個(gè)頭文件. 主要是stdafx.h Project Setting->C/C++ -> Category(Precompiled header)->not using Precompiled header試試
下面是msdn的說(shuō)法: Fatal Error C1010 unexpected end of file while looking for precompiled header directive A precompiled header was specified, but it did not contain a precompiled header directive. This error can be caused by specifying an incorrect file as a header file, or by specifying an include file with the /Yu (Use Precompiled Header) command line option that is not listed in the source file as an include file.
注:http://hi.baidu.com/chinapegasus/blog/item/27ede14f949d5133afc3ab9a.html
2.
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16 >
[Project] --> [Settings] --> 選擇"Link"屬性頁(yè), 在Project Options中將/subsystem:console改成/subsystem:windows
2. Console子系統(tǒng)設(shè)置錯(cuò)誤, 提示: LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16 >
控制臺(tái)項(xiàng)目要使用Console子系統(tǒng), 而不是Windows, 設(shè)置:
[Project] --> [Settings] --> 選擇"Link"屬性頁(yè), 在Project Options中將/subsystem:windows改成/subsystem:console
3. 程序入口設(shè)置錯(cuò)誤, 提示: msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain@16
通常, MFC項(xiàng)目的程序入口函數(shù)是WinMain, 如果編譯項(xiàng)目的Unicode版本, 程序入口必須改為wWinMainCRTStartup, 所以需要重新設(shè)置程序入口:
[Project] --> [Settings] --> 選擇"Link"屬性頁(yè), 在Category中選擇Output, 再在Entry-point symbol中填入wWinMainCRTStartup, 即可
4. 線程運(yùn)行時(shí)庫(kù)設(shè)置錯(cuò)誤, 提示: nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
這是因?yàn)镸FC要使用多線程時(shí)庫(kù), 需要更改設(shè)置:
[Project] --> [Settings] --> 選擇"C/C++"屬性頁(yè), 在Category中選擇Code Generation, 再在Use run-time library中選擇Debug Multithreaded或者multithreaded 咸魚(yú)游俠(75374355) 12:11:11 其中, Single-Threaded
單線程靜態(tài)鏈接庫(kù)(release版本) Multithreaded
多線程靜態(tài)鏈接庫(kù)(release版本) multithreaded DLL
多線程動(dòng)態(tài)鏈接庫(kù)(release版本) Debug Single-Threaded
單線程靜態(tài)鏈接庫(kù)(debug版本) Debug Multithreaded
多線程靜態(tài)鏈接庫(kù)(debug版本) Debug Multithreaded DLL
多線程動(dòng)態(tài)鏈接庫(kù)(debug版本)
單線程: 不需要多線程調(diào)用時(shí), 多用在DOS環(huán)境下
多線程: 可以并發(fā)運(yùn)行
靜態(tài)庫(kù): 直接將庫(kù)與程序Link, 可以脫離MFC庫(kù)運(yùn)行
動(dòng)態(tài)庫(kù): 需要相應(yīng)的DLL動(dòng)態(tài)庫(kù), 程序才能運(yùn)行
release版本: 正式發(fā)布時(shí)使用 debug版本: 調(diào)試階段使用
文章出處:http://www.diybl.com/course/3_program/c++/cppjs/2008619/126655.html
1、fatal error C1010: unexpected end of file while looking for precompiled header directive。
尋找預(yù)編譯頭文件路徑時(shí)遇到了不該遇到的文件尾。(一般是沒(méi)有#include "stdafx.h")
2、fatal error C1083: Cannot open include file: 'R…….h': No such file or directory
不能打開(kāi)包含文件“R…….h”:沒(méi)有這樣的文件或目錄。
3、error C2011: 'C……': 'class' type redefinition
類“C……”重定義。
4、error C2018: unknown character '0xa3'
不認(rèn)識(shí)的字符'0xa3'。(一般是漢字或中文標(biāo)點(diǎn)符號(hào))
5、error C2057: expected constant expression
希望是常量表達(dá)式。(一般出現(xiàn)在switch語(yǔ)句的case分支中)
6、error C2065: 'IDD_MYDIALOG' : undeclared identifier
“IDD_MYDIALOG”:未聲明過(guò)的標(biāo)識(shí)符。
7、error C2082: redefinition of formal parameter 'bReset'
函數(shù)參數(shù)“bReset”在函數(shù)體中重定義。
8、error C2143: syntax error: missing ':' before '{'
句法錯(cuò)誤:“{”前缺少“;”。
9、error C2146: syntax error : missing ';' before identifier 'dc'
句法錯(cuò)誤:在“dc”前丟了“;”。
10、error C2196: case value '69' already used
值69已經(jīng)用過(guò)。(一般出現(xiàn)在switch語(yǔ)句的case分支中)
11、error C2509: 'OnTimer' : member function not declared in 'CHelloView'
成員函數(shù)“OnTimer”沒(méi)有在“CHelloView”中聲明。
12、error C2511: 'reset': overloaded member function 'void (int)' not found in 'B'
重載的函數(shù)“void reset(int)”在類“B”中找不到。
13、error C2555: 'B::f1': overriding virtual function differs from 'A::f1' only by return type or calling convention
類B對(duì)類A中同名函數(shù)f1的重載僅根據(jù)返回值或調(diào)用約定上的區(qū)別。
14、error C2660: 'SetTimer' : function does not take 2 parameters
“SetTimer”函數(shù)不傳遞2個(gè)參數(shù)。
15、warning C4035: 'f……': no return value
“f……”的return語(yǔ)句沒(méi)有返回值。
16、warning C4553: '= =' : operator has no effect; did you intend '='?
沒(méi)有效果的運(yùn)算符“= =”;是否改為“=”?
17、warning C4700: local variable 'bReset' used without having been initialized
局部變量“bReset”沒(méi)有初始化就使用。
18、error C4716: 'CMyApp::InitInstance' : must return a value
“CMyApp::InitInstance”函數(shù)必須返回一個(gè)值。
19、LINK : fatal error LNK1168: cannot open Debug/P1.exe for writing
連接錯(cuò)誤:不能打開(kāi)P1.exe文件,以改寫(xiě)內(nèi)容。(一般是P1.Exe還在運(yùn)行,未關(guān)閉)
20、error LNK2001: unresolved external symbol "public: virtual _ _thiscall C……::~C……(void)"
連接時(shí)發(fā)現(xiàn)沒(méi)有實(shí)現(xiàn)的外部符號(hào)(變量、函數(shù)等)。
function call missing argument list 調(diào)用函數(shù)的時(shí)候沒(méi)有給參數(shù)。
member function definition looks like a ctor, but name does not match enclosing class 成員函數(shù)聲明了但沒(méi)有使用
unexpected end of file while looking for precompiled header directive 在尋找預(yù)編譯頭文件時(shí)文件意外結(jié)束,編譯不正常終止可能造成這種情況。
如何拋出(throw)由CUserException派生的異常?
當(dāng)我試圖捕獲(catch)一個(gè)派生類異常時(shí),我得到以下錯(cuò)誤"error C2039:'classCMyException': is not a member of 'CMyException' 'classCMyException': undeclared identifier 'IsKindOf': cannot convert parameter 1 from 'int*' to 'const struct CRuntimeClass*"
你必需通過(guò)使用DECLARE_DYNAMIC()和IMPLEMENT_DYNAMIC()宏來(lái)使你的CMyException類可以動(dòng)態(tài)地創(chuàng)建。CATCH宏希望能夠得到關(guān)于被拋出類的運(yùn)行時(shí)刻信息。
異常類一定要從CUserException中派生出來(lái)嗎?
不,CUserException中的"User"僅僅指用戶產(chǎn)生的異常。而把它當(dāng)作你所能派生的唯一異常是種常見(jiàn)的誤解。
如何從HDC建立一個(gè)CDC類?
有時(shí)Windows API將會(huì)給你一個(gè)DC句柄,你可以通過(guò)它建立一個(gè)CDC類。例如:下拉式列表、組合框和按鈕。通過(guò)hDC你將接收到繪制消息。下面是將HDC轉(zhuǎn)換成你更熟悉的CDC的程序段。你也可以將該技巧用在其他任何MFC類和Windows句柄的轉(zhuǎn)換中。
void MyODList::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
{
CDC myDC;
myDC.Attach(lpDrawItem->hDC);
//在此插入其他需要的代碼。
//如果你不將句柄分離,它將被刪除,從而導(dǎo)致問(wèn)題。
myDC.Detach();
}
另一個(gè)方法是調(diào)用CDC類的FromHandle方法:
CDC * pDC = CDC:FromHandle(lpDrawItem->hDC);
目前還不清楚哪種方法更優(yōu)越―使用FromHandle()的錯(cuò)誤也許會(huì)更少些,因?yàn)樗灰竽惴蛛x(detach)句柄。
如何從磁盤(pán)上讀取256色位圖文件?
當(dāng)前,MFC并不支持直接讀取和顯示DIB文件和BMP文件。然而,有很多樣例應(yīng)用程序能夠說(shuō)明如何完成該項(xiàng)任務(wù)。第一個(gè)例子是MFC樣例程序DIBLOOK。樣例MULTDOCS用DIBLOOK提供的相同源代碼來(lái)讀取并顯示DIB文件和BMP文件。其他兩個(gè)VC++中附帶的例子是SDK軟件包中的DIBVIEW程序和SHOWDIB程序。
如何改變一個(gè)視圖的大小?
通常,你可以調(diào)用函數(shù)MoveWindow()來(lái)改變窗口的大小。在用MFC庫(kù)開(kāi)發(fā)的應(yīng)用程序中, 視圖是被框架窗口所圍繞的一個(gè)子窗口。為了改變一個(gè)視圖的大小,你可以通過(guò)調(diào)用函數(shù)GetParentFrame()來(lái)得到框架窗口的指針,然后調(diào)用函數(shù)MoveWindow()來(lái)改變父窗口的大小。當(dāng)父框架窗口改變大小時(shí),視圖也會(huì)自動(dòng)地改變大小來(lái)適應(yīng)父窗口。
如何改變一個(gè)CFormView的大小?
要想詳細(xì)了解的話,你可以看有關(guān)Visual C++基礎(chǔ)知識(shí)的文章Q98598 《Using CFormView in SDI and MDI Applications》。基本上,在從CFormView類派生出來(lái)的類中,你必須覆蓋函數(shù)OnInitialUpdate()。其他有關(guān)建立CFormView的細(xì)節(jié)問(wèn)題,可以從該文章中獲得。
在類ClikethisView中聲明如下函數(shù):
virtual void OnInitialUpdate();
在ClikethisView的代碼中,函數(shù)如下:
void ClikethisView::OnInitialUpdate()
{
//使窗口與主對(duì)話框同樣大小
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit( /*FALSE*/ );
}
如何使用一個(gè)文檔模板的新視圖?
在用AppWizard創(chuàng)建的應(yīng)用程序中,你有兩種選擇:改變當(dāng)前視圖的派生關(guān)系或者建立一個(gè)新視圖并且在你的MDI程序中同時(shí)利用新視圖和原先的視圖。
為了創(chuàng)建一個(gè)新視圖,你可以用ClassWizard由CView派生一個(gè)新的類。當(dāng)新類創(chuàng)建以后,利用新視圖或修改由AppWizard提供的視圖,兩者的步驟是相同的。
修改視類的頭文件,從而將所有對(duì)CView類的引用改名為你所想要的名稱。本例中的類由CScrollView派生而來(lái)。通常,這個(gè)步驟包括對(duì)類的改變,視類將由如下方式派生而來(lái):
class CMyView : public CScrollView
修改視類的實(shí)現(xiàn)文件,從而將所有對(duì)CView的引用改名為你所想要的名稱。這包括將IMPLEMENT_DYNCREATE那一行的語(yǔ)句改為:
IMPLEMENT_DYNCREATE(CMyView, CScrollView)
將BEGIN_MESSAGE_MAP那一行的語(yǔ)句改為:
BEGIN_MESSAGE_MAP(CMyView, CScrollView)
并且將其他所有的CView改成CScrollView.
假如你修改的視圖是由AppWizard生成的,那么就不需要作更多的修改了。而如果你在創(chuàng)建一個(gè)新視圖,先在CWinApp::InitInstance()函數(shù)中找到對(duì)AddDocTemplate()函數(shù)的調(diào)用。AddDocTemplate()函數(shù)的第三個(gè)參數(shù)是RUNTIME_CLASS(CSomeView),用CMyView來(lái)代替CSomeView,就可以將當(dāng)前視圖改為新視圖。在MDI應(yīng)用程序中,你可以增加第二個(gè)AddDocTemplate()函數(shù)調(diào)用來(lái)使用多視圖類型,將RUNTIME_CLASS(CSomeView)改為RUNTIME_CLASS (CMyView)。
要想獲得更多的信息請(qǐng)參閱Q99562中相關(guān)文章《Switching Views in a Single Document Interface Program》 。
如何改變視圖的背景色?
你可以通過(guò)處理WM_ERASEBKGND消息來(lái)改變CView、CFrameWnd或CWnd對(duì)象的背景色。請(qǐng)看如下的程序段:
BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
// 設(shè)置所要求背景色的刷子
CBrush backBrush(RGB(255, 128, 128));
// 保存舊刷子
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); // 擦除所需的區(qū)域
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
而我則用如下方法解決這個(gè)問(wèn)題:
HBRUSH dlgtest::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
switch (nCtlColor)
{
case CTLCOLOR_BTN:
case CTLCOLOR_STATIC:
{
pDC->SetBkMode(TRANSPARENT);
}
case CTLCOLOR_DLG:
{
CBrush* back_brush;
COLORREF color;
color = (COLORREF) GetSysColor(COLOR_BTNFACE);
back_brush = new CBrush(color);
return (HBRUSH) (back_brush->m_hObject);
}
}
return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}
如何得到當(dāng)前視圖?
最佳方法是將視圖當(dāng)作一個(gè)參數(shù)來(lái)傳遞。如果不能這樣做,但你確信它是當(dāng)前激活文檔和當(dāng)前激活視圖的話,你也可以得到該視圖。具體細(xì)節(jié)見(jiàn)Visual C++文章Q108587《Get Current CDocument or CView from Anywhere》。
簡(jiǎn)單說(shuō)來(lái),用:
((CFrameWnd*) AfxGetApp()->m_pMainWnd))->GetActiveDocument()
和:
((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->GetActiveView()
來(lái)得到文檔和視圖。一個(gè)好的方法是將它們封裝在你的CMyDoc和CMyView類的靜態(tài)函數(shù)中,并且核對(duì)它們是否屬于正確的RUNTIME_CLASS。然而,假如這個(gè)視圖不是當(dāng)前激活視圖或者你在運(yùn)行OLE本地激活,這樣將不成功。
如何在一個(gè)文檔中建立多個(gè)視圖?
CDocTemplate::CreateNewFrame()函數(shù)創(chuàng)建MFC MDI應(yīng)用程序中的文檔的附加視圖。為了調(diào)用該函數(shù),要指定一個(gè)指向CDocument對(duì)象(指將為之建立視圖的文檔)的指針和一個(gè)指向可從中復(fù)制屬性的框架窗口的指針。一般情形下,該函數(shù)的第二個(gè)參數(shù)為NULL。
當(dāng)應(yīng)用程序調(diào)用函數(shù)CreateNewFrame()時(shí),該函數(shù)就創(chuàng)建一個(gè)框架窗口和在該窗口內(nèi)的視圖。框架窗口和它的視圖的類型由與CreateNewFrame()函數(shù)調(diào)用指定的文檔相關(guān)的文檔摸板(CDocTemplate)決定。
Visual C++中的CHKBOOK MFC樣例程序也演示了如何為文檔建立附加的框架和視圖。檢查CHKBOOK.CPP文件中的CChkBookApp::OpenDocumentfile()函數(shù)。
另一個(gè)用函數(shù)CreateNewFrame()的例子是MULTVIEW樣本程序。
CreateNewFrame()函數(shù)建立了一個(gè)框架和一個(gè)視圖,而不僅僅是一個(gè)視圖。假如CreateNewFrame()函數(shù)不能完全符合你的需要,可參考CreateNewFrame()函數(shù)的源程序來(lái)了解對(duì)建立結(jié)構(gòu)和視圖所必須的步驟。
如何在MDI程序中得到所有的視圖?
你必須用一些文檔中沒(méi)有記載的函數(shù):
CDocument::GetFirstViewPosition(); // DOCCORE.CPP
CDocument::GetNextView(); // DOCCORE.CPP
CMultiDocTemplate::GetFirstDocPosition(); // DOCMULTI.CPP
CMultiDocTemplate::GetNextDoc(); // DOCMULTI.CPP
你還需要與CWinApp的成員m_templateList打交道。
注意:在MFC 版本4.0中已改變。現(xiàn)在已經(jīng)有一個(gè)叫CDocManager的類可以幫助你顯示所有的視圖和文檔。請(qǐng)參考《MFC Internals》獲得更詳細(xì)的信息。
如何建立一個(gè)可用鼠標(biāo)拉動(dòng)的CScrollView類
在CIS上從MSMFC庫(kù)下載AUTOSV.LZH。這個(gè)程序告訴你如何實(shí)現(xiàn)一個(gè)輔助消息循環(huán)來(lái)管理鼠標(biāo)的活動(dòng),并提供了鉤掛來(lái)對(duì)代碼進(jìn)行定制。這是一個(gè)免費(fèi)軟件。
一定要用視圖/文檔結(jié)構(gòu)嗎?
MFC并不一定要求你使用文檔/視圖結(jié)構(gòu)。查看HELLO、 MDI和HELLOAPP例子―它們就沒(méi)有用那種結(jié)構(gòu)。大多數(shù)MFC特性都可以在非文檔/視圖應(yīng)用程序中得到運(yùn)用。但是當(dāng)你不用文檔 / 視圖結(jié)構(gòu)時(shí),你確實(shí)會(huì)失去一些特性,例如打印預(yù)覽和許多OLE特性。
如何得到當(dāng)前文檔?
請(qǐng)?jiān)敿?xì)參閱"如何得到當(dāng)前視圖?"章節(jié)。
文檔何時(shí)被析構(gòu)?
在SDI程序中,程序退出后文檔就被刪除。在MDI程序中,與該文檔相關(guān)的最后一個(gè)視圖關(guān)閉時(shí)文檔就被刪除。為了在SDI和MDI中同時(shí)用這個(gè)文檔,你應(yīng)該在虛函數(shù)DeleteContents()函數(shù)中刪除該文檔的數(shù)據(jù),而不是在析構(gòu)器中。
如何建立多文檔?
為了加入對(duì)附加文檔類型的支持,你可以在CWinApp派生類中創(chuàng)建和注冊(cè)附加CmultiDocTemplate對(duì)象。這種方法已經(jīng)在MULTDOCS樣例程序中得以說(shuō)明。將一個(gè)附加文檔類型加入到MFC程序的一般步驟如下:
用AppWizard來(lái)創(chuàng)建一個(gè)新的文檔類和視圖類。
用資源編輯器增加新的資源字串來(lái)支持新的文檔類。要想知道關(guān)于文檔樣板字符串格式的更多內(nèi)容,請(qǐng)參閱"如何理解文檔樣板字符串"。
用資源編輯器增加附加的應(yīng)用程序圖標(biāo)和菜單資源。注意,這些資源中每一個(gè)的ID都必須與在步驟2中創(chuàng)建的文檔模板字符串的ID是相同的。這個(gè)ID被CmultiDocTemplate類用來(lái)識(shí)別與附加文檔類型相關(guān)的資源。
在應(yīng)用程序的InitInstance()函數(shù)中,創(chuàng)建了另一個(gè)CMultiDocTemplate對(duì)象并且用CWinApp::AddDocTemplate()函數(shù)來(lái)注冊(cè)。例如:
CMultiDocTemplate* pDocTemplate2 = new CMultiDocTemplate(
IDR_DOC2TYPE, RUNTIME_CLASS(CDoc2),
RUNTIME_CLASS(CMDIChildWnd),RUNTIME_CLASS(CView2));
AddDocTemplate(pDocTemplate2);
最后,將定制的序列化和繪圖代碼加入到你的新文檔和視圖類中。
如何得到一個(gè)打開(kāi)文檔的列表?
下面的程序段指明如何得到用CDocTemplate對(duì)象建立的所有文檔的指針列表。
下面的程序段中,CMyApp由CWinApp派生而來(lái)。變量m_templateList是一個(gè)CPtrList對(duì)象,它是CwinApp的成員變量,包含一個(gè)所有文檔模板指針的列表。文檔模板函數(shù)GetFirstDocPosition()和GetNextDoc()被用來(lái)在文檔模板列表中進(jìn)行迭代來(lái)得到每一個(gè)文檔模板。
void CMyApp::GetDocumentList(CObList * pDocList)
{
ASSERT(pDocList->IsEmpty());
POSITION pos = m_templateList.GetHeadPosition();
while (pos)
{
CDocTemplate* pTemplate =
(CDocTemplate*)m_templateList.GetNext(pos);
POSITION pos2 = pTemplate->GetFirstDocPosition();
while (pos2)
{
CDocument * pDocument;
if ((pDocument=pTemplate->GetNextDoc(pos2)) != NULL)
pDocList->AddHead(pDocument);
}
}
}
在參考手冊(cè)或在線幫助中,有兩個(gè)CdocTemplate類的公共成員函數(shù)沒(méi)有被說(shuō)明。然而, 這些公共成員函數(shù)在CDocTemplate類中被定義,并且為在打開(kāi)文檔的列表中前后搜索提供了簡(jiǎn)單的支持。
這些函數(shù)如下:
Function virtual POSITION GetFirstDocPosition() const;
調(diào)用該函數(shù)得到在打開(kāi)的文檔列表中與模板相關(guān)聯(lián)的第一個(gè)文檔的位置。返回的POSITION的值能夠被GetNextDoc成員函數(shù)反復(fù)使用。
Function Virtual CDocument* GetNextDoc(POSITION& rPosition) const;
rPostion是前面調(diào)用GetNextDoc 或GetFirstDocPosition成員函數(shù)返回的POSITION值。這個(gè)值不能是NULL。調(diào)用該函數(shù)來(lái)在所有打開(kāi)的文檔中進(jìn)行迭代。該函數(shù)返回被rPosition所標(biāo)識(shí)的文檔并將rPosition設(shè)置為列表中的下一個(gè)文檔的POSITION值。假如所檢索的是列表中的最后一個(gè)文檔,rPosition將被設(shè)為空值。
注意,這僅對(duì)MFC3.2版本或更低版本有效,對(duì)MFC4.0版本請(qǐng)參考下面:
void CMyApp::DoSomethingToAllDocs()
{
CObList pDocList;
POSITION pos = GetFirstDocTemplatePosition();
while(pos)
{
CDocTemplate* pTemplate = GetNextDocTemplate(pos);
POSITION pos2 = pTemplate->GetFirstDocPosition();
while(pos2)
{
CDocument* pDocument;
if(pDocument = pTemplate->GetNextDoc(pos2))
pDocList.AddHead(pDocument);
}
}
if(!pDocList.IsEmpty()){
pos = pDocList.GetHeadPosition();
while(pos)
{
//為每一個(gè)文檔調(diào)用CDocument函數(shù)
( (CDocument*)pDocList.GetNext(pos) )
->UpdateAllViews(NULL);
}
}
如何使我的程序在啟動(dòng)時(shí)不創(chuàng)建一個(gè)新文檔?
在程序的InitInstance中的ProcessShellCommand函數(shù)之前加入: cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
格式:文件指針名=fopen(文件名,使用文件方式)
參數(shù):
文件名 意義
"C:/temp/temp.txt" 文件 C:\temp\temp.txt
文件使用方式 意 義
“rt” 只讀打開(kāi)一個(gè)文本文件,只允許讀數(shù)據(jù)
“wt” 只寫(xiě)打開(kāi)或建立一個(gè)文本文件,只允許寫(xiě)數(shù)據(jù)
“at” 追加打開(kāi)一個(gè)文本文件,并在文件末尾寫(xiě)數(shù)據(jù)
“rb” 只讀打開(kāi)一個(gè)二進(jìn)制文件,只允許讀數(shù)據(jù)
“wb” 只寫(xiě)打開(kāi)或建立一個(gè)二進(jìn)制文件,只允許寫(xiě)數(shù)據(jù)
“ab” 追加打開(kāi)一個(gè)二進(jìn)制文件,并在文件末尾寫(xiě)數(shù)據(jù)
“rt+” 讀寫(xiě)打開(kāi)一個(gè)文本文件,允許讀和寫(xiě)。用fseek確定讀寫(xiě)位置,寫(xiě)多少覆蓋多少,
后面的內(nèi)容保留。因?yàn)榇疟P(pán)空間是連續(xù)的,所以你不能在中間插入,在中間一旦
寫(xiě)入就是覆蓋與寫(xiě)入內(nèi)容等長(zhǎng)的那些內(nèi)容。
“wt+” 讀寫(xiě)打開(kāi)或建立一個(gè)文本文件,允許讀寫(xiě)
“at+” 讀寫(xiě)打開(kāi)一個(gè)文本文件,允許讀,或在文件末追加數(shù)據(jù)
“rb+” 讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件,允許讀和寫(xiě)
“wb+” 讀寫(xiě)打開(kāi)或建立一個(gè)二進(jìn)制文件,允許讀和寫(xiě)
“ab+” 讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件,允許讀,或在文件末追加數(shù)據(jù)
對(duì)于文件使用方式有以下幾點(diǎn)說(shuō)明:
1. 文件使用方式由r,w,a,t,b,+六個(gè)字符拼成,各字符的含義是:
r(read): 讀
w(write): 寫(xiě)
a(append): 追加
t(text): 文本文件,可省略不寫(xiě)
b(banary): 二進(jìn)制文件
+: 讀和寫(xiě)
2. 凡用“r”打開(kāi)一個(gè)文件時(shí),該文件必須已經(jīng)存在,且只能從該文件讀出。
3. 用“w”打開(kāi)的文件只能向該文件寫(xiě)入。若打開(kāi)的文件不存在,則以指定的文件名建立該文件,若打開(kāi)的文件已經(jīng)存在,則將該文件刪去,重建一個(gè)新文件。
4. 若要向一個(gè)已存在的文件追加新的信息,只能用“a ”方式打開(kāi)文件。但此時(shí)該文件必須是存在的,否則將會(huì)出錯(cuò)。
5. 在打開(kāi)一個(gè)文件時(shí),如果出錯(cuò),fopen將返回一個(gè)空指針值NULL。在程序中可以用這一信息來(lái)判別是否完成打開(kāi)文件的工作,并作相應(yīng)的處理。
如果成功的打開(kāi)一個(gè)文件, fopen()函數(shù)返回文件指針, 否則返回空指針
(NULL)。由此可判斷文件打開(kāi)是否成功。
fclose()函數(shù)用來(lái)關(guān)閉一個(gè)由fopen()函數(shù)打開(kāi)的文件 , 其調(diào)用格式為:
int fclose(FILE *stream);
該函數(shù)返回一個(gè)整型數(shù)。當(dāng)文件關(guān)閉成功時(shí), 返回0, 否則返回一個(gè)非零值。
可以根據(jù)函數(shù)的返回值判斷文件是否關(guān)閉成功
1)(CStuDlg*)AfxGetMainWnd() //AfxGetMainWnd() 得到主程序的指針!~~
2)GetDlgItem(IDC_EDIT3) //GetDlgItem()得到控件指針!~~
3)GetDlgItem(IDC_ENGLISH)->SetFocus(); //SetFocus()光標(biāo)所在區(qū)!~~~
4)SetGlgItemText(dlg,IDC_WIDTH,"");設(shè)置控件的名稱!~~
5)MessageBox(
LPCTSTR lpszText,//消息字符串
LPCTSTR lpszCaption=NULL,//消息框標(biāo)題
UINT nType=MB_OK //消息框風(fēng)格
);