vc編程經驗總結

作者:風中的流沙       出處:http://blog.vckbase.com/flowsand/archive/2006/01/27/17448.html

 

VC常見入門問題總結

1:fatal error C1010: unexpected end of file while looking for precompiled header directive該如何解決
    如果發生錯誤的文件是由其他的C代碼文件添加進入當前工程而引起的,則Alt+F7進入當前工程的Settings,選擇C/C++選項卡,從Category組合框中選中Precompiled Headers,選擇Not Using Precompiled headers。確定
    如果發生錯誤的文件原本是該工程中的,則檢查該文件頭部有沒有#include "stdafx.h"語句,沒有的話添加。
    如果還不行,也有可能是定義的類或結構體等最後忘了加分號,注意一下。
2:fatal error RC1015: cannot open include file 'afxres.h'.該如何解決
    #include "afxres.h"語句是在.rc文件中的,而afxres.h文件在VC的安裝目錄中的./VC98/MFC/INCLUDE目錄中,所以着重查一下Tools菜單中Options對話框中的Directories中的包括文件的路徑是否正確,是否在VC的安裝路徑中,不是的話,改過來,如果這方面沒問題,則到其他機器中拷貝afxres.h到相應的目錄中
3:Dll分配的內存塊,應用程序釋放,結果報異常。
    用GlobalAlloc()代替new, 用GlobalFree() 代替delete就不會出錯了
    其實還有一個辦法,就是把dll的Settings的C/C++選項卡的Code Generation的Use Run-time liberary改成Debug Multithreaded DLL,在Release版本中改成Multithreaded DLL,就可以直接使用new和delete了,沒問題
    比較規範點的做法一般是DLL分配的內存由DLL釋放。在DLL中加一個函數釋放內存不是更好嗎。
4:發現打印預覽的圖形明顯比屏幕顯示圖形小,怎麼辦?
    這多半是CDC映射模式的選擇引起的,缺省狀態下,選擇的是MM_TEXT模式,MM_TEXT以設備的像素點爲單位,而不同設備的像素點的大小不同,打印機的分辨率比顯示器要高很多,所以導致同樣圖形在打印時候變小。解決之道是統一使用其他定長的映射模式,比如MM_HIMETRIC等等(CDC::SetMapMode()改變映射模式)
5:CString、char*、string、int、_bstr_t、CTime、COleDateTime等等的相互轉換,如何判斷一個字符串是一個浮點數?

#include<string>
using namespace std;
#include <COMDEF.H>

{
CString strCString="ABC";
char strchar[256],*pstr;

pstr=(LPSTR)(LPCTSTR)strCString; //CString---->char*
strcpy(strchar,(LPSTR)(LPCTSTR)strCString); //CString---->char[]

_bstr_t strbstr=pstr; //char*---->_bstr_t
WCHAR *strWCHAR=strbstr; //b_str_t--->UNICODE

strbstr=strWCHAR;
pstr=strbstr; //UNICODE---->char*

strCString="10";
int istr=atoi((LPSTR)(LPCTSTR)strCString); //CString、char[]、char*------>int
strCString.Format("%d",istr); //int----->CString
sprintf(strchar,"%d",istr); //int----->char[]

pstr=new char[256]; //字符串申請空間
strcpy(pstr,"ABC"); //字符串賦值
delete []pstr; //字符串釋放

string strstring="ABC";
pstr=(char*)strstring.c_str(); //string---->char*

strCString="2003-10-27 6:24:37"; //CString--->COleDateTime
COleVariant vtime(strCString);
vtime.ChangeType(VT_DATE);
COleDateTime time4=vtime;

 

COleDateTime time1(1977,4,16,2,2,2); //COleDataTime--->CTime
SYSTEMTIME systime;
VariantTimeToSystemTime(time1, &systime);
CTime tm(systime);

time_t time2=tm.GetTime(); //CTime--->time_t
COleDateTime time3(time2); //time_t--->COleDateTime

//判斷字符串是否是某種類型
CString sValue("123.1");
COleVariant vValue(sValue);

BOOL bStrIsFloat = (SUCCEEDED(VariantChangeType(&vValue, &vValue, 0, VT_R8)) && sValue.Find('.') != -1);
if(bStrIsFloat)
{
AfxMessageBox("浮點");
}
}

6:如何建立一個UNICODE應用程序?

建立一個應用程序,打開Alt+F7 settings選項,選擇C/C++選項卡,在Preprocessor definenation中加上_UNICODE,在Link選項卡中,在Category選擇框中選擇Output,在Entry-point symbol編輯框中,添加wWinMainCRTStartup確定。

注意調試UNICODE程序時,需要在安裝時VC選擇所有選項,否則會缺少動態庫和相應的.lib文件


7:ADO操作數據庫表,更新出現問題
在打開數據庫前,添加如下語句試一下pRecordSet->CursorLocation = adUseClient;

 

IntefOptics.lib(IntefOptics.dll) : error LNK2005: "public: bool __thiscall CIntvnOptics::NewtonRingsCreate(int,double,int,int,int,int)" (?NewtonRingsCreate@CIntvnOptics@@QAE_NHNHHHH@Z) already defined in IntvnOptics.obj

這類錯誤是什麼導致? 不要說rebuild all, 因爲我已經做了不下百次了
LIB裏面有和IntvnOptics.cpp裏面一樣的函數實現。估計你在編譯庫的時候將NewtonRingsCreate的實現寫在頭文件裏面,然後你使用庫的那個CPP文件include了那個頭文件。
ll.h
//
void func()
{
//...
}
ll.cpp
#include "ll.h"
以上兩個文件編譯成lib,使用庫的時候
ul.cpp
#include "ll.h"
這時候ul裏面也連接了func,lib裏面也有func。
解決方法:
1、實現放到CPP裏面
或者
2、使用inline修飾
inline void func()
{
//...
}
大家分享一下如何用MFC做實際項目的經驗
希望大家一起分享一下如何用MFC做實際項目的經驗,中秋湊個熱鬧。呵呵。
1、界面風格和控件
2、消息循環、多線程、數據庫相關
3、數據結構和算法相關
4、其他

初學MFC的時候,大家最先接觸的就是界面吧。
雖然說界面不是特別重要,但確實讓人頭痛。
弄來弄去,大多是控件搞不定。(在這個版這樣的問題好多:))
至於消息循環機制,我覺得我們用到不多。
MFC都幫我們做好了。不過有一些注意事項。
上一次我做多線程的時候死鎖了,阿行大哥就是用消息機制幫我解決的。
另外,rtdb大哥還贈了我1000分,使我能夠繼續提問。(太感謝了)
這個版好心人不少。感謝之餘,我在這裏也和大家分享一下。

1、
剛開始的時候,爲了把界面做得好看,
我在www.codeproject.comwww.codeguru.com上面找到了一些好用的控件。
如ButtonST、TruecolorToolbar、GradientProgressCtrl、CoolToolbar等
控件。可能大家也用過。它們都很好用,而且有演示程序下載,邊學邊用,
用對比法和增減法,這兩個方法學MFC挺管用的。
後來在www.vkbase.com看到了一個換膚的ActiveX控件,很好用。
做出來的界面特好看。大家去下載看看。
可惜對組合框等控件支持不夠。(可能是小弟不會:))

後來做數據庫的時候,我公司的高手說選擇越簡單的控件越好。
我剛開始用DataGrid,直接綁定數據庫。
他們建議用原始的Grid控件,獨立於具體的數據庫。
Grid控件沒有(也不需要!)編輯和組合框支持。編輯的時候跳出對話框來解決。

現在我做的一個項目的界面是單文檔多個formview切換。(這個界面挺古老的吧)
曾經用過屬性頁控件,現在用了Tab控件和對話框嵌入,感覺這個挺好的。

遇到控件問題的時候,我常看msdn,上面的實例真好。
現在有問題來msdn,我都是先搜索一下,其實大多數問題都已經有帖子解答。
這樣可以節省自己和別人的時間。
記住每個控件都是一個窗口是有幫助的。

2、
多線程的時候尤其要注意一個問題:MFC幫我們開的線程是界面線程。
如果我們以後再開的線程是工作者線程,那麼界面主線程不能阻塞。
如果界面主線程阻塞了,相當於消息泵阻塞了。
我上次犯的錯誤就是讓其他工作者線程發一個消息來讓主線程解除阻塞。結果死鎖。
解決方法是將其他線程改爲界面線程。
還有一個問題,創建新線程的時候要小心,它有一個CRuntimeClass*的參數。
它要CreateObject()創建一個新的線程,然後把線程指針返回。
CSerialPortEx* g_pPort = new CSerialPortEx;
CRuntimeClass* IOClass  = g_pPort->GetRuntimeClass();
g_pPort = (CSerialPortEx*)AfxBeginThread(IOClass);
上面的代碼將使g_pPort無法訪問CSerialPortEx內部的變量。
通過增加一個臨時變量來解決。如下:
CSerialPortEx* TempPort = new CSerialPortEx;
CRuntimeClass* IOClass  = TempPort->GetRuntimeClass();
g_pPort = (CSerialPortEx*)AfxBeginThread(IOClass);
delete TempPort;
類似的場合不少。如在用對話框嵌入標籤的時候再一次創建了對話框。
出現了實際上存在兩個對話框,無法訪問原來對話框上的控件。
現在我一看到CRuntimeClass*就會特別小心。
我在解決這些問題的時候用的方法是調試和增減法。並不是從書上得來。
如果有差錯,請各位指出來。呵呵。
還有一個問題是進度條對話框上的控件不能及時顯示,(消息循環暫時受阻塞)
阿行大哥用在用戶代碼中加入消息循環解決。也可以開一個線程。

數據庫我都沒有怎麼做過。我的項目不大。
想請教各位設計的時候需要什麼考慮,還有上面說的“使用簡單的控件”是否合理。
有沒有必要自己寫一個數據庫類,用SQL語句進行訪問。

3、
數據結構我學得太爛了,現在非常後悔。不過只得加把勁了。
幸虧我現在只用到鏈表和數組。呵呵。
我覺得鏈表和數組都有欠缺。
象我的項目,串口數據在不停的上來,根據上來的數據監控下面機器的狀態。
如果用數組,長度是固定的。
如果用鏈表,有可能用戶暫時不在監控界面。(假設長達幾個小時)
幾個小時之內的數據用鏈表一直來存儲着。
然後等用戶一切換回監控,就一下子從頭到尾刷新?!
如果什麼都不用,直接用後一個狀態覆蓋前一個,那麼就無法顯示一系列的過程。
正在考慮用一個固定長度的鏈表。

4、
還有其他沒考慮到的地方,大家提出來討論吧。

vc做程序最重要的就是小心,小心再小心,每做一步自己都要多運行幾遍,分別在debug,release模式下運行運行,
看看有沒有內存泄漏,越界等錯誤,等到最後才發現那就慘了

1。程序運行穩定,儘量用老辦法,不瞭解的函數不要隨便用。
2。功能要簡單實用。
3。不要追求功能的完美。完美的功能是不可能的。
4。程序一有bug,必須糾正後才能前進

 

10進制:0-9,只有十進制的纔有正負之分。
16進制:以0x或0X開頭,0-9+a-f(A-F)
8進制:以0開頭,0-7
默認的數是double型,有f/F表示float型,有l/L表示long double型。

C語言中,#include “stdio.h”
格式控制符:
d:十進制
o:八進制
x:十六進制
c:單個字符
f:浮點數(double/float)
e/E:浮點數(輸入和f一樣,科學計數發輸出)
s:以’/0’結束的字符串
u:十進制無符號
g:f/e中較短的一種

指定字符寬:
*:刪除空格前剩餘數
0:前面補0,而不是補空格
格式控制:%  +/-  m  .  n  l/h  □
+/-:對齊方式,默認+,右對齊;-左對齊。
m:輸出寬度(float時候包含小數點),大於時按實際輸出,小於時補空格
. :小數點,float/double時候才用
n:小數點後面的位數,float/double時候才用
l/h:表示是long/shot
□:格式控制符d/o/x/c/f/e/s/u/g

 

設置窗口的透明度(win2000以上)
-----------------------------------
第一步 定義功能

typedef BOOL (FAR PASCAL * FUNC1)(
  HWND hwnd,           // handle to the layered window
  COLORREF crKey,      // specifies the color key
  BYTE bAlpha,         // value for the blend function
  DWORD dwFlags        // action
);


第二步 實現代碼

在OnInitDialog中加入下列代碼(如果在SDI裏面,應該是在OnCreat裏面添加)

.....
HMODULE hModule = GetModuleHandle("user32.dll");
FUNC1 SetLayeredWindowAttributes;
SetLayeredWindowAttributes =  (FUNC1) GetProcAddress (hModule, _T( "SetLayeredWindowAttributes" ) );

// 設置分層擴展標記
SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE) | 0x80000L);
// 70% alpha
SetLayeredWindowAttributes(GetSafeHwnd(), 0, (255 * 70) / 100, 0x2);


工作完成,怎麼樣,現在你可以運行你的程序來查看效果,即使背景變化也能立刻反映到你的窗口當中,這一點比金山詞霸的效果要好。

 

第三步:如何除去透明選項?

// 除去分層擴展標記
SetWindowLong(GetSafeHwnd(),, GWL_EXSTYLE,
        GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE) & ~ 0x80000L);
// 重畫窗口
RedrawWindow();

 

1、調試程序的時候有簡單到複雜:碰到程序運行出錯時,可以先把一些程序註釋掉,只留很少的一部分,確保程序的正確運行,然後再逐段逐段代碼的釋放,很容易發現問題所在。

2、單獨做試驗:對程序中用到的一些獨立的模塊和功能,如果不是太熟悉或則把握不準,可以單獨的寫一個小的程序去做試驗,驗證用法以及結果。不要在很大的工程中調試某些獨立的模塊。

3、仔細認真地作試驗。在研究一個新的控件或功能時,要象對待正式程序一樣認真的對待,否則如果出現錯誤,你就有可能得出一個錯誤的結論,一旦用到整個的程序中就會是一個很難發現的錯誤,浪費大量的時間去查找其他的代碼。

4、有時候錯誤的程序會莫名其妙的運行正常,但你並沒有找到出錯的原因。這時千萬不要高興太,應該繼續調試和試驗,一定要把錯誤找出來。只要你找不出來,這個錯誤就是一個炸彈,不一定什麼時候發作。

5、進行數據庫操作的時候,碰到比較複雜的SQL語句,最好先在數據庫中執行測試你的SQL語句,以保證該語句的正確性。

6、建議在操作數據庫的時候使用“事務處理”,否則程序在運行時(特別在網絡中)會遇到意想不到的問題,如:網絡不穩定可能會使你的操作只執行一部分。

7、長期連續運行的程序中,一些複雜的功能不要在定時器(OnTimer)中完成,而儘量使用線程完成,我的感覺是,放在線程中要比定時器穩定的多。(只是我自己的看法)

 

下面是一個VC調試觀察窗口的格式化符號表格,希望對大家有幫助
——————————————————————————————————
符號          格式                例子          輸出
d或者i      有符號十進制整數     -42,d         -42
U           無符號十進制整數     42,d          42
O           無符號八進制整數     42,o          052
x或X        十六進制整數         42,x           0x0000002a或0x0000002A
H           爲d,I,u,o,x顯示前綴  42,hx          0X002a
F           有符號浮點數         1.5,f         1.500000
E           有符號科學計數法     1.5,e          1.500000e+000
G           壓縮的有符號浮點數   1.5,g          1.5
C           字符                 42,c           '*'
S           ANSI字符串           "bugs",s       "bugs"
Su          Unicode字符串        "bugs",st      "bugs"
Hr          HRESULT和Win32錯誤碼 0X06,hr        The handle is invalid
wm          Windows消息號        0x01,wm        WM_CREATE
[digits]    顯示數組元素         s,5            顯示s[]前五個值

 

AND_CATCHAND_CATCH
AND_CATCH(exception_class,exception _object_point_name)
說明:

定義一個代碼塊,它用於獲取廢除當前TRY塊中的附加異常類型。使用CATCH宏以獲得一個異常類型,然後使用AND_CATCH宏獲得隨後的異常處理代碼可以訪問異常對象(若合適的話)已得到關於異常的特別原因的更多消息。在AND_CATCH塊中調用THROW_LAST宏以便把處理過程移到下個外部異常框架。AND_CATCH可標記CATCH或AND_CATCH塊的末尾。

註釋:
AND_CATCH塊被定義成爲一個C++作用域(由花括號來描述)。若用戶在此作用域定義變量,那麼記住他們只在此作用域中可以訪問。他也用於exception_object_pointer_name變量。 
  
ASSERT
ASSERT(booleanExpression)
說明:
計算變量的值。如果結構的值爲0,那麼此宏便打印一個診斷消息並且成訊運行失敗。如果條件爲非0,那麼什麼也不做。 診斷消息的形式爲: assertion failed in file in line 其中name是元文件名,num是源文件中運行失敗的中斷號。 在Release版中,ASSERT不計算表達式的值也就不中斷程序。如果必須計算此表達式的值且不管環境如何那麼用VERIFY代替ASSERT。
註釋:
ASSERT只能在Debug版中用
 
ASSERT_VAILD
ASSERT_VAILD(pObject)
說明:
用於檢測關於對象的內部狀態的有效性。ASSERT_VALID調用此對象的AssertValid成員函數(把它們作爲自己的變量來傳遞)。在Release版中ASSERT_VALID什麼也不做。在DEBUG版中,他檢查指針,以不同於NULL的方式進行檢查,並調用對象自己的AssertValid成員函數。如果這些檢測中有任何一個失敗的話,那麼他會以與ASSERT相同的方法顯示一個警告的消息。
註釋:
此函數只在DEBUG版中有效。
 
BEGIN_MESSAGE_MAP
BEGIN_MESSAGE_MAP(the class,baseclass)
說明:
使用BEGIN_MESSAGE_MAP開始用戶消息映射的定義。在定義用戶類函數的工具(.cpp)文件中,以BEGIN_MESSAGE_MAP宏開始消息映射,然後爲每個消息處理函數增加宏項,接着以END_MESSAGE_MAP宏完成消息映射。
 
CATCH
CATCH(exception_class,exception_object_pointer_name)
說明:
使用此用定義一個代碼塊,此代碼用來獲取當前TRY塊中都一個異常類型。異常處理代碼可以訪問異常對象,如何合適的話,就會得到關於異常的特殊原因的更多消息。調用THROW_LAST宏以把處理過程一下一個外部異常框架,如果exception-class是類CExceptioon,那麼會獲取所有異常類型。用戶可以使用CObject::IsKindOf成員函數以確定那個特別異常被排除。一種獲取異常的最好方式是使用順序的AND_CATCH語句,每個帶一個不同的異常類型。此異常類型的指針由宏定義,用戶不必定義。
註釋:
此CATCH塊被定義作一個C++範圍(由花括號描述)。如用戶在此範圍定義變量,那麼它們只在吃範圍內可以訪問。他還可以用於異常對象的指針名。
 
DEBUG_NEW
#define new DEBUG_NEW
說明:
幫助查找內存錯誤。用戶在程序中使用DEBUG_NEW,用戶通常使用new運算符來從堆上分配。在Debug模式下(但定義了一個DEBUG符號),DEBUG_NEW爲它分配的每個對象記錄文件名和行號。然後,在用戶使用CMemoryState::DumpAllObjectSince成員函數時,每個以DEBUG_NEW分配的對象分配的地方顯示出文件名和行號。 爲了使用DEBUG_NEW,應在用戶的資源文件中插入以下指令: #define new DEBUG_NEW 一旦用戶插入本指令,預處理程序將在使用new的地方插入DEBUG_NEW,而MFC作其餘的工作。但用戶編譯自己的程序的一個發行版時,DEBUG_NEW便進行簡單的new操作,而且不產生文件名和行號消息。
 
DECLARE_DYNAMIC
DECLARE_DYNAMIC(class_name)
說明:
但從CObject派生一個類時,此宏增加關於一個對象類的訪問運行時間功能。把DECLARE_DYNAMIC宏加入類的頭文件中,然後在全部需要訪問詞類對象的.CPP文件中都包含此模塊。如果像所描述那樣使用DELCARE_DYNAMIC和IMPLEMENT_DYNAMIC宏,那麼用戶便可使用RUNTIME_CLASS宏和CObject::IsKindOf函數以在運行時間決定對象類。如果DECLARE_DYNAMIC包含在類定義中,那麼IMPLEMETN_DYNAMIC必須包含在類工具中。
 
DECLARE_DYNCREATE
DECLARE_DYNCREATE(class_name)
說明:
使用DECLARE_DYNCRETE宏以便允許CObject派生類的對象在運行時刻自動建立。主機使用此功能自動建立新對象,例如,但它在串行化過程中從磁盤讀一個對象時,文件及視圖和框架窗應該支持動態建立,因爲框架需要自動建立它。把DECLARE_DYNCREATE宏加入類的.H文件中,然後在全部需要訪問此類對象的.CPP文件中包含這一模式。如果DECLARE_DYNCREATE包含在類定義中,那麼IMPLEMENT_DYNCREATE必須包含在類工具中。

 


This is an example on how to implement a floating window application. I have used a timer control, in combination with the Point class to specify the position of the main form in the desktop. Combining those two elements I simulated the floating behavior of the main form re-defining its position on every Tick event fired by the Timer control.

比如要讓“d:/move/debug/move.exe"自動運行,只要用下面這個API函數就行了!

WritePrivateProfileString(_T("windows"),_T("load"),"d://move//debug//move.exe",_T("C://windows//win.ini"));
VC 和 MFC 的一些常見問題 
--------------------------------------------------------------------------------

Q:如何拋出(throw)由CUserException派生的異常?

A:當我試圖捕獲(catch)一個派生類異常時,我得到以下錯誤"error C2039:'classCMyException': is not a member of 'CMyException' 'classCMyException': undeclared identifier 'IsKindOf': cannot convert parameter 1 from 'int*' to 'const struct CRuntimeClass*"
你必需通過使用DECLARE_DYNAMIC()和IMPLEMENT_DYNAMIC()宏來使你的CMyException類可以動態地創建。CATCH宏希望能夠得到關於被拋出類的運行時刻信息。
異常類一定要從CUserException中派生出來嗎?

不,CUserException中的"User"僅僅指用戶產生的異常。而把它當作你所能派生的唯一異常是種常見的誤解。

Q:如何從hDC建立一個CDC類?
有時Windows API將會給你一個DC句柄,你可以通過它建立一個CDC類。例如:下拉式列表、組合框和按鈕。通過hDC你將接收到繪製消息。下面是將hDC轉換成你更熟悉的CDC的程序段。你也可以將該技巧用在其他任何MFC類和Windows句柄的轉換中。

void MyODList::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
{
    CDC myDC;
    myDC.Attach(lpDrawItem->hDC);
    //在此插入其他需要的代碼。

    //如果你不將句柄分離,它將被刪除,從而導致問題。
    myDC.Detach();
}
另一個方法是調用CDC類的FromHandle方法:
            CDC * pDC = CDC:FromHandle(lpDrawItem->hDC);
目前還不清楚哪種方法更優越―使用FromHandle()的錯誤也許會更少些,因爲它不要求你分離(detach)句柄。

Q:如何從磁盤上讀取256色位圖文件?
A:當前,MFC並不支持直接讀取和顯示DIB文件和BMP文件。然而,有很多樣例應用程序能夠說明如何完成該項任務。第一個例子是MFC樣例程序DIBLOOK。樣例MULTDOCS用DIBLOOK提供的相同源代碼來讀取並顯示DIB文件和BMP文件。其他兩個VC++中附帶的例子是SDK軟件包中的DIBVIEW程序和SHOWDIB程序。

Q:如何改變一個視圖的大小?
A:通常,你可以調用函數MoveWindow()或者SetWindowPos()來改變窗口的大小。在用MFC庫開發的應用程序中, 視圖是被框架窗口所圍繞的一個子窗口。爲了改變一個視圖的大小,你可以通過調用函數GetParentFrame()來得到框架窗口的指針,然後調用函數MoveWindow()/SetWindowPos()來改變父窗口的大小。當父框架窗口改變大小時,視圖也會自動地改變大小來適應父窗口。

Q:如何改變一個CFormView的大小?
A:要想詳細瞭解的話,你可以看有關Visual C++基礎知識的文章:HOWTO: Use CFormView in SDI and MDI Applications。基本上,在從CFormView類派生出來的類中,你必須覆蓋函數OnInitialUpdate()(因爲CFormView::public CScrollView)。其他有關建立CFormView的細節問題,可以從該文章中獲得。

/*-----------------------------------------------
SUMMARY
The CFormView class provides a convenient method to place controls into a view that is based on a dialog box template.
MORE INFORMATION
The following steps describe how to create an AppWizard generated application using the CFormView as the default view.

Use the AppWizard to generate an SDI or MDI application skeleton, stopping at step six of the AppWizard.
At step 6 of the AppWizard, select the view class and specify CformView as the base class using the Base class combo box. This will insert a dialog template with the proper styles set for your project's resource file.

Override the OnUpdate() member function and call UpdateData() as documented in the CFormView documentation to update the member variables with the current document data and to perform dialog data exchange (DDX). NOTE: UpdateData is not virtual and calling the base class ensures that the derived class DoDataExchange is called through standard polymorphism. The CFormView documentation states to call, not override UpdateData.

If you would like to set the initial size of the form view, override the OnInitialUpdate() function. The text below provides additional information about this step, which is slightly different in an SDI or MDI application.

Changing the Size of an SDI Main Frame Around a CFormView

To change the size of the main frame of an SDI application (that uses CFormView as its view class) to be the appropriate size for the form you designed in App Studio, override the OnInitialUpdate() function in your class derived from CFormView, as follows:
      void CMyFormView::OnInitialUpdate()
      {
         CFormView::OnInitialUpdate();
         GetParentFrame()->RecalcLayout();
         ResizeParentToFit(); // default argument is TRUE
      }
The ResizeParentToFit() function does not prevent the form from changing size when the user changes the size of the application main frame (scroll bars are added automatically if needed). To modify the style of the frame window that is the parent of a form view, you can override the PreCreateWindow() function in the CMainFrame class generated by AppWizard. For example, to remove the WS_THICKFRAME style and prevent the user from changing the size of the window, declare PreCreateWindow() in MAINFRM.H and add the following code to MAINFRM.CPP:

      BOOL CMainFrame::PreCreateWindow(CREATESTRUCT &cs)
      {
         cs.style &= ~WS_THICKFRAME;
         return CFrameWnd::PreCreateWindow(cs);
      }
     
Changing the Size of an MDI Child Frame Around a CFormView

The process of changing the size of an MDI child frame is similar to changing the size of a main frame for an SDI application, as explained above. However, the RecalcLayout() call is not required.

To change the size of an MDI child frame around a form view, override the OnInitialUpdate() function in your class derived from CFormView as follows:

      void CMDIFormView::OnInitialUpdate()
      {
         CFormView::OnInitialUpdate();
         ResizeParentToFit(); // Default argument is TRUE.
      }
If the application overrides the default argument to the ResizeParentToFit() function, essentially the same consequences occur as for an SDI application, as explained above. In addition, the child window may be too large for the enclosing MDI main frame or for the entire screen.

To change the style of the MDI child frame (for example, to remove the WS_THICKFRAME style so the user cannot change the size of the window), derive an MDI child window class and override the PreCreateWindow function as demonstrated in the SDI example above.
Closing an MDI Form with a Button
To create a button on a form that closes the document, use ClassWizard to add a message handler for the BN_CLICKED message to the CFormView class. Make sure that the buttons in CFormView do not have the default IDOK or IDCANCEL identifiers. If they do, ClassWizard creates incorrect entries in the message map and incorrect functions for the buttons.

Once the message handler is in place, you can simulate the Close command on the File menu with the following code:

      void CMyForm::OnClickedButton1()
      {
         PostMessage(WM_COMMAND, ID_FILE_CLOSE);
      }
This method to close a form prompts the user to save the file if the IsModified() member function associated with the document returns TRUE.
*/------------------------------------------------
在類ClikethisView中聲明如下函數:
  virtual void OnInitialUpdate();

在ClikethisView的代碼中,函數如下:

  void ClikethisView::OnInitialUpdate()
  {
      //使窗口與主對話框同樣大小
      CFormView::OnInitialUpdate();
      GetParentFrame()->RecalcLayout();
      ResizeParentToFit( /*FALSE*/ );//must be false;
  }

 


Q:如何在一個文檔中建立多個視圖?
A:CDocTemplate::CreateNewFrame()函數創建MFC MDI應用程序中的文檔的附加視圖。爲了調用該函數,要指定一個指向CDocument對象(指將爲之建立視圖的文檔)的指針和一個指向可從中複製屬性的框架窗口的指針。一般情形下,該函數的第二個參數爲NULL。

當應用程序調用函數CreateNewFrame()時,該函數就創建一個框架窗口和在該窗口內的視圖。框架窗口和它的視圖的類型由與CreateNewFrame()函數調用指定的文檔相關的文檔摸板(CDocTemplate)決定。

CreateNewFrame()函數建立了一個框架和一個視圖,而不僅僅是一個視圖。假如CreateNewFrame()函數不能完全符合你的需要,可參考CreateNewFrame()函數的源程序來了解對建立結構和視圖所必須的步驟。
輔助函數:
///////////////////////////////////////////////////////////
// Create a new view based on the document template
// parameter and associated with the given document object

CFrameWnd* UserCreateNewWindow( CDocTemplate* pTemplate,
                              CDocument* pDocument )
{
ASSERT_VALID( pTemplate );
ASSERT_VALID( pDocument );

// 1 - Create the new frame window
// (will in turn create the associated view)
CFrameWnd* pFrame = pTemplate->CreateNewFrame(pDocument, NULL );
if( pFrame == NULL )
{
// Window creation failed
TRACE0( "Warning: failed to create new frame./n" );
return NULL;
}
ASSERT_KINDOF( CFrameWnd, pFrame );

// 2 - Tell the frame to update itself
// (and its child windows)
pTemplate->InitialUpdateFrame( pFrame, pDocument );

// 3 - Return a pointer to the new frame window object
return pFrame;
}

Q:如何在MDI程序中得到所有的視圖?

A:你必須用一些文檔中沒有記載的函數:

  CDocument::GetFirstViewPosition(); // DOCCORE.CPP
  CDocument::GetNextView(); // DOCCORE.CPP
  CMultiDocTemplate::GetFirstDocPosition(); // DOCMULTI.CPP
  CMultiDocTemplate::GetNextDoc(); // DOCMULTI.CPP
 

你還需要與CWinApp的成員m_templateList打交道。
注意:在MFC 版本4.0中已改變。現在已經有一個叫CDocManager的類可以幫助你顯示所有的視圖和文檔。請參考《MFC Internals》獲得更詳細的信息。
詳細說明參見《深入淺出MFC》

Q:文檔何時被析構?

A:在SDI程序中,程序退出後文檔就被刪除。在MDI程序中,與該文檔相關的最後一個視圖關閉時文檔就被刪除。爲了在SDI和MDI中同時用這個文檔,你應該在虛函數DeleteContents()函數中刪除該文檔的數據,而不是在析構器中。

 


Q:如何把一個項目變成 Unicode 版的:

A:1、把"Setting" "C/C++" "Preprocessor definitions" 中的_MBCS 改爲 _UNICODE。
    2、把"Setting" "Link" 中 Category 選爲 "Output", 在 Entry-point symbol 中輸入"wWinMainCRTStartup"。
   
Q:How to Add Horizontal Scrolling to a List Box
A normal Windows list box does not  implement a default horizontal scrolling. In order to do that, the horizontal extent must be modified:


// Add string to the ListBox
m_listBox.AddString(m_sAddString);

// Adjust Horizontal Scrolling Extent (if necessary)
CClientDC dc(m_listBox);
CSize size = dc.GetTextExtent(m_sAddString, m_sAddString.GetLength());

if (size.cx > m_listBox.GetHorizontalExtent())
m_listBox.SetHorizontalExtent(size.cx);

A sample of an Horizontal Scrolling List Box in an MFC Class can be found in the Microsoft Knowledge Base (Article ID: Q146437)

Q: I'm trying to call a Windows API, but the compiler gives an undeclared identifier error (C2065). Why? (top)

A:The most likely reason is that the header files you are using to build are out-of-date and do not include the features you're trying to use. The headers that came with Visual C++ 6 are extremely old, and if you are still using them, you will run into this problem often. You can get updated header files by downloading the Platform SDK from Microsoft. Microsoft recently created an online installer, much like Windows Update, called SDK Update. If you do not want to use this page (it requires you to install an ActiveX control), you can download the SDK CAB files and install the SDK from that local copy. You can also order the SDK on CD from the SDK Update site.

If you have downloaded the latest header files and are still getting compiler errors, read on.

The Windows header files can be used to build programs for any version of Windows starting with Windows 95 and NT 3.51. Since not all APIs are present in all versions of Windows, there is a system that prevents you from using APIs that aren't available in the Windows version you are targeting.

This system uses preprocessor symbols to selectively include API prototypes. The symbols are:

WINVER: Windows version (applies to 9x/Me and NT)
_WIN32_WINDOWS: Windows 9x/Me version
_WIN32_WINNT: Windows NT version
_WIN32_IE: Common controls version
By default, you can only use functions in Windows 95, NT 3.51, and pre-IE3 common controls. To use APIs introduced in later versions of Windows or the common controls, you need to #define the above symbols correctly before including any Windows headers.

Q: I'm trying to call a Windows API, but the linker gives an unresolved external error (LNK2001) on the API name. Why? (top)

A:When you call a function whose code is not in your program itself, such as any Windows API, you need to tell the linker where the function is so it can store information about the function in your EXE. This is done with an import library. An import library is a LIB file that contains the list of functions exported from its corresponding DLL. For example, kernel32.lib contains the exports for kernel32.dll. When Windows loads your EXE, it reads this information, loads the correct DLL, and resolves the function calls.

The VC AppWizard creates projects with the most commonly-used LIBs (such as kernel32.lib, user32.lib, etc.) already listed in the linker options, but if you use call APIs in other DLLs, you'll need to add the corresponding LIB files.

Let's take for example the API PathAddBackslash(). When you get an unresolved external error on this API, you need to find out which LIB file its definition is contained in. Read the MSDN page on PathAddBackslash(), and at the bottom you'll see: "Import Library: Shlwapi.lib". That tells you that you must add shlwapi.lib to your linker options.

To add import libraries to the linker options, click Project->Settings and go to the Link tab. Set the Category combo box to General, then add the LIB filenames in the Object/library modules edit box.

Q:Why do I get an unresolved external error (LNK2001) on main() when I make a release build of my ATL project? (top)

A:Release builds of ATL projects contain an optimization whereby the project does not link with the C runtime library (CRT) in order to reduce the size of your binary. If you use any functions from the CRT (for example, string manipulation functions) or classes from the C++ library, you need to link with the CRT.

In your project options, go to the C/C++ tab and select the Preprocessor category. Remove the symbol _ATL_MIN_CRT from the preprocessor defines, which will turn off this optimization.

Search MSDN for "lnk2001 atl" and see KB article Q166480 (question #4) for more details.

Q:Why do I get an unresolved external (LNK2001) error on _beginthreadex and _endthreadex? (top)

A:This happens when you compile a project that uses MFC, but your compiler settings are set to use the single-threaded version of the C runtime library (CRT). Since MFC uses threads, it requires the multithreaded CRT. Since the single-threaded CRT doesn't contain _beginthreadex() and _endthreadex(), you get a linker error on those two functions.

To change your CRT setting, click Project->Settings and go to the C/C++ tab. Set the Category combo box to Code Generation. In the Use run-time library combo box, chose one of the multithreaded versions of the CRT. For debug builds, choose Debug Multithreaded or Debug Multithreaded DLL. For release builds, choose Multithreaded or Multithreaded DLL. The versions that say "DLL" use MSVCRT.DLL, while the others do not depend on that DLL.

Q: I have a dialog that does some lengthy processing, and I need to have a Cancel button so the user can abort the processing. How do I get the Cancel button to work? (top)

A:First off, the reason the UI doesn't respond to the mouse is that your program is single-threaded, which means it is not pumping messages in the dialog's message queue while the thread is busy doing the processing.

You have two choices, either move the processing to a worker thread, or keep the dialog single-threaded and periodically poll your message queue during your processing. Multithreading is beyond the scope of this FAQ, but see the Threads, Processes & Inter-Process Communication section of CodeProject for more info. As to the second solution, here is MFC code that will pump any messages waiting in your message queue:

void ProcessMessages()
{
CWinApp* pApp = AfxGetApp();
MSG msg;

  while ( PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE ))
      pApp->PumpMessage();
}
Call ProcessMessages() periodically in the code that does the lengthy processing.

Q:How do I keep a window on top of all other windows? (top)

A:To make your window topmost:

// MFC:
  wndYourWindow.SetWindowPos ( &wndTopMost, 0, 0, 0, 0, 0,
                               SWP_NOMOVE|SWP_NOSIZE );

// Win32 API:
  SetWindowPos ( hwndYourWindow, HWND_TOPMOST, 0, 0, 0, 0,
                 SWP_NOMOVE|SWP_NOSIZE );
To revert back to normal:

// MFC:
  wndYourWindow.SetWindowPos ( &wndNoTopMost, 0, 0, 0, 0,
                               SWP_NOMOVE|SWP_NOSIZE );

// Win32 API:
  SetWindowPos ( hwndYourWindow, HWND_NOTOPMOST, 0, 0, 0, 0,
                 SWP_NOMOVE|SWP_NOSIZE );
Q: How do I highlight an entire row of a list view control in report mode? (top)

A:The full-row-select feature is enabled by setting an extended style of the list control.

// MFC:
  wndYourList.SetExtendedStyle ( LVS_EX_FULLROWSELECT );

// Win32 API:
  ListView_SetExtendedListViewStyle ( hwndYourList, LVS_EX_FULLROWSELECT );

 


CListCtrl 幾點經驗 zhucde(【風間蒼月】)
部分轉載)
每個List控件都有一個CHeaderCtrl。且它的ID是0。
CHeaderCtrl* pHeader =(CHeaderCtrl*)m_listCtrl.GetDlgItem(0);
即使List控件非report模式,Header控件也存在,只是此時它的尺寸爲0。
可利用以下代碼使得控件的第一列自適應大小:
m_listctrl.SetColumnWidth( 0, LVSCW_AUTOSIZE );
List 控件中的圖標初始化時可如下設置:
m_listCtrl.InsertItem( LVIF_TEXT | LVIF_IMAGE, nRow, sItemText, 0, 0, nImage
, NULL);
在運行中需動態改變可調用SetItem()函數.
m_listCtrl.SetItem( 0, 0, LVIF_IMAGE, NULL, nImage, 0, 0, 0 );
刪去圖標可將nImage設置爲-1。

以下代碼可將列表框的第一列限定大小:
BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
        HD_NOTIFY   *pHDN = (HD_NOTIFY*)lParam;
        if((pHDN->hdr.code == HDN_BEGINTRACKW || pHDN->hdr.code == HDN_BEGIN
TRACKA)
                && pHDN->iItem == 0)            // Prevent only first (col#
0) from resizing
        {
                *pResult = TRUE;                // disable tracking
                return TRUE;                    // Processed message
        }
        return CListCtrl::OnNotify(wParam, lParam, pResult);
}


選定cell
CListCtrl::OnClick(...)
{
    int column;
    CRect m_rect;
    //the function below is provided in CListCtrl inPlace editing
    int index = GetRowColumnIndex(point, &column);
    if(index == -1)return;
    int offset = 0;
    for(int i = 0; i < column; i++)
      offset += GetColumnWidth(i);
    //Get the rectangle of the label and the icon
    GetItemRect(index, &m_rect, LVIR_BOUNDS);
    m_rect.left += offset + 4;
    //Get the columnWidth of the selected column
    m_rect.right = m_rect.left + GetColumnWidth(column);
    Update(index);
    CClientDC dc(this);    //this is the pointer of the current view
    dc.DrawFocusRect(m_rect);
}

Select NonFirst cell:

void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
        CListCtrl::OnLButtonDown(nFlags, point);
        int index;
        point.x = 2;
        if( ( index = HitTest( point, NULL )) != -1 )
        {
                SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
                                LVIS_SELECTED | LVIS_FOCUSED);
        }
}


HitTestEx的代碼如下:
判斷點擊的是哪一列:
// HitTestEx - Determine the row index and column index for a point
// Returns - the row index or -1 if point is not over a row
// point - point to be tested.
// col  - to hold the column index
int CMyListCtrl::HitTestEx(CPoint &point, int *col) const
{
int colnum = 0;
int row = HitTest( point, NULL );
if( col ) *col = 0;
// Make sure that the ListView is in LVS_REPORT
if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
  return row;
// Get the top and bottom row visible
row = GetTopIndex();
int bottom = row + GetCountPerPage();
if( bottom > GetItemCount() )
  bottom = GetItemCount();
// Get the number of columns
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount();
// Loop through the visible rows
for( ;row <=bottom;row++)
{
  // Get bounding rect of item and check whether point falls in it.
  CRect rect;
  GetItemRect( row, &rect, LVIR_BOUNDS );
  if( rect.PtInRect(point) )
  {
   // Now find the column
   for( colnum = 0; colnum < nColumnCount; colnum++ )
   {
    int colwidth = GetColumnWidth(colnum);
    if( point.x >= rect.left
     && point.x <= (rect.left + colwidth ) )
    {
     if( col ) *col = colnum;
     return row;
    }
    rect.left += colwidth;
   }
  }
}
return -1;
}


選中一定範圍內的Item
// SelItemRange - Selects/Deselect a range of items
// Returns              - The number of new items selected
// bSelect              - TRUE to select, FALSE to deselect
// nFirstItem           - index of first item to select
// nLastItem            - index of last item to select
int CMyListCtrl::SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem)
{
        // make sure nFirstItem and nLastItem are valid
        if( nFirstItem >= GetItemCount() || nLastItem >= GetItemCount() )
                return 0;
        int nItemsSelected = 0;
        int nFlags = bSelect ? 0 : LVNI_SELECTED;
        int nItem = nFirstItem - 1;
        while( (nItem = GetNextItem( nItem, nFlags )) >=0
                        && nItem <= nLastItem )
        {
                nItemsSelected++;
                SetItemState(nItem, bSelect ? LVIS_SELECTED : 0, LVIS_SELECT
ED );
        }
        return nItemsSelected;
}

 


SetHeaderBitmap:

static int _gnCols = 5;
static int _gnColSize[] =
{
18,21,22,18,380
};
static CString _gcsColLabel[] =
{
_T("x"),
_T("x"),
_T("x"),
_T("x"),
_T("Description:")
};
void CRightView::BuildColumns()
{
// Insert the columns into the list control
LV_COLUMN lvCol;
lvCol.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
for (int i = 0; i < _gnCols; ++i)
{
  lvCol.iSubItem = i;
  lvCol.pszText = (char*)(LPCTSTR)_gcsColLabel[i];
  lvCol.cx = _gnColSize[i];
  lvCol.fmt = LVCFMT_LEFT;
  m_ListCtrl->InsertColumn(i, &lvCol);
}
for (int x = 0; x < _gnCols-1; x++)
  SetHeaderBitmap(x, nHeaderBmps[x], HDF_STRING);
}
void CRightView::SetHeaderBitmap(int nCol, int nBitmap, DWORD dwRemove)
{
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
HD_ITEM hdi;
hdi.mask = HDI_FORMAT;
pHeader->GetItem (nCol, &hdi);
hdi.mask = HDI_BITMAP | HDI_FORMAT;
hdi.fmt  |= HDF_BITMAP;
hdi.hbm = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
  MAKEINTRESOURCE(nBitmap),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
if (dwRemove)
  hdi.fmt &= ~dwRemove;
pHeader->SetItem (nCol, &hdi);
}

續上:
刪除功能的實現(VCBASE)

要實現刪除功能,必須取得選中表項的數和表項總數,並且需要從後向前進行依次刪除,其原因是每個表項被刪除後,其後各表項的索引號均會發生遞減變化,如果採取從前向後刪除的方法,就會造成無法正常刪除選中的表項,其功能代碼如下:

void CVCLISTDlg::OnDel() //刪除按鈕功能

{ // TODO: Add your control notification handler code here

int i,iState;

int nItemSelected=m_ListCtrl.GetSelectedCount();//所選表項數

int nItemCount=m_ListCtrl.GetItemCount();//表項總數

if(nItemSelected<1) return;

for(i=nItemCount-1;i>=0;i--){

iState=m_ListCtrl.GetItemState(i,LVIS_SELECTED);

if(iState!=0) m_ListCtrl.DeleteItem(i);

}

}

通過專用按鈕來實現排序功能,如本文的排序按鈕對應的功能代碼如下:(VCBASE)

void CVCLISTDlg::OnSort()

{ // TODO: Add your control notification handler code here

m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,0);

 

VC++中的文件操作


各種關於文件的操作在程序設計中是十分常見,如果能對其各種操作都瞭如指掌,就可以根據實際情況找到最佳的解決方案,從而在較短的時間內編寫出高效的代碼,因而熟練的掌握文件操作是十分重要的。本文將對Visual C++中有關文件操作進行全面的介紹,並對在文件操作中經常遇到的一些疑難問題進行詳細的分析。
  1.文件的查找
  當對一個文件操作時,如果不知道該文件是否存在,就要首先進行查找。MFC中有一個專門用來進行文件查找的類CFileFind,使用它可以方便快捷地進行文件的查找。下面這段代碼演示了這個類的最基本使用方法。
  CString strFileTitle;
  CFileFind finder;
  BOOL bWorking = finder.FindFile("C://windows//sysbkup//*.cab");
  while(bWorking)
  {
  bWorking=finder.FindNextFile();
  strFileTitle=finder.GetFileTitle();
  }
  2.文件的打開/保存對話框
  讓用戶選擇文件進行打開和存儲操作時,就要用到文件打開/保存對話框。MFC的類CFileDialog用於實現這種功能。使用CFileDialog聲明一個對象時,第一個BOOL型參數用於指定文件的打開或保存,當爲TRUE時將構造一個文件打開對話框,爲FALSE時構造一個文件保存對話框。
  在構造CFileDialog對象時,如果在參數中指定了OFN_ALLOWMULTISELECT風格,則在此對話框中可以進行多選操作。此時要重點注意爲此CFileDialog對象的m_ofn.lpstrFile分配一塊內存,用於存儲多選操作所返回的所有文件路徑名,如果不進行分配或分配的內存過小就會導致操作失敗。下面這段程序演示了文件打開對話框的使用方法。
  CFileDialog mFileDlg(TRUE,NULL,NULL,
  OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT,
  "All Files (*.*)|*.*||",AfxGetMainWnd());
  CString str(" ",10000);
  mFileDlg.m_ofn.lpstrFile=str.GetBuffer(10000);
  str.ReleaseBuffer();
  POSITION mPos=mFileDlg.GetStartPosition();
  CString pathName(" ",128);
  CFileStatus status;
  while(mPos!=NULL)
  {
  pathName=mFileDlg.GetNextPathName(mPos);
  CFile::GetStatus( pathName, status );
  }
  3.文件的讀寫
  文件的讀寫非常重要,下面將重點進行介紹。文件讀寫的最普通的方法是直接使用CFile進行,如文件的讀寫可以使用下面的方法:
    //對文件進行讀操作
    char sRead[2];
    CFile mFile(_T("user.txt"),CFile::modeRead);
    if(mFile.GetLength()<2)
    return;
    mFile.Read(sRead,2);
    mFile.Close();
    //對文件進行寫操作
    CFile mFile(_T("user.txt "), CFile::modeWrite|CFile::modeCreate);
    mFile.Write(sRead,2);
    mFile.Flush();
    mFile.Close();
    雖然這種方法最爲基本,但是它的使用繁瑣,而且功能非常簡單。我向你推薦的是使用CArchive,它的使用方法簡單且功能十分強大。首先還是用CFile聲明一個對象,然後用這個對象的指針做參數聲明一個CArchive對象,你就可以非常方便地存儲各種複雜的數據類型了。它的使用方法見下例。
    //對文件進行寫操作
    CString strTemp;
    CFile mFile;
    mFile.Open("d://dd//try.TRY",CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite);
    CArchive ar(&mFile,CArchive::store);
    ar<<  ar.Close();
    mFile.Close();
    //對文件進行讀操作
    CFile mFile;
    if(mFile.Open("d://dd//try.TRY",CFile::modeRead)==0)
    return;
    CArchive ar(&mFile,CArchive::load);
    ar>>strTemp;
      ar.Close();
    mFile.Close();
    CArchive的 << 和>> 操作符用於簡單數據類型的讀寫,對於CObject派生類的對象的存取要使用ReadObject()和WriteObject()。使用CArchive的ReadClass()和WriteClass()還可以進行類的讀寫,如:
    //存儲CAboutDlg類
    ar.WriteClass(RUNTIME_CLASS(CAboutDlg));
    //讀取CAboutDlg類
    CRuntimeClass* mRunClass=ar.ReadClass();
    //使用CAboutDlg類
  CObject* pObject=mRunClass->CreateObject();
     ((CDialog* )pObject)->DoModal();
    雖然VC提供的文檔/視結構中的文檔也可進行這些操作,但是不容易理解、使用和管理,因此雖然很多VC入門的書上花費大量篇幅講述文檔/視結構,但我建議你最好不要使用它的文檔。關於如何進行文檔/視的分離有很多書介紹,包括非常著名的《Visual C++ 技術內幕》。
    如果你要進行的文件操作只是簡單的讀寫整行的字符串,我建議你使用CStdioFile,用它來進行此類操作非常方便,如下例。
    CStdioFile mFile;
    CFileException mExcept;
    mFile.Open( "d://temp//aa.bat", CFile::modeWrite, &mExcept);
    CString string="I am a string.";
    mFile.WriteString(string);
  mFile.Close();
   4.臨時文件的使用
 
  正規軟件經常用到臨時文件,你經常可以會看到C:/Windows/Temp目錄下有大量的擴展名爲tmp的文件,這些就是程序運行是建立的臨時文件。臨時文件的使用方法基本與常規文件一樣,只是文件名應該調用函數GetTempFileName()獲得。它的第一個參數是建立此臨時文件的路徑,第二個參數是建立臨時文件名的前綴,第四個參數用於得到建立的臨時文件名。得到此臨時文件名以後,你就可以用它來建立並操作文件了,如:
    char szTempPath[_MAX_PATH],szTempfile[_MAX_PATH];
    GetTempPath(_MAX_PATH, szTempPath);
    GetTempFileName(szTempPath,_T ("my_"),0,szTempfile);
    CFile m_tempFile(szTempfile,CFile:: modeCreate|CFile:: modeWrite);
    char m_char='a';
    m_tempFile.Write(&m_char,2);
    m_tempFile.Close();
    5.文件的複製、刪除等
    MFC中沒有提供直接進行這些操作的功能,因而要使用SDK。SDK中的文件相關函數常用的有CopyFile()、CreateDirectory()、DeleteFile()、MoveFile()。它們的用法很簡單,可參考MSDN。


**************************************************************************************************
×××××××××××××××××××××××××××××××××××××××××××××××××
**************************************************************************************************
如何進行文件操作

[1]顯示對話框,取得文件名

CString FilePathName;
CFileDialog dlg(TRUE);///TRUE爲OPEN對話框,FALSE爲SAVE AS對話框
if (dlg.DoModal() == IDOK)
   FilePathName=dlg.GetPathName();

相關信息:CFileDialog 用於取文件名的幾個成員函數:
假如選擇的文件是C:/WINDOWS/TEST.EXE
則(1)GetPathName();取文件名全稱,包括完整路徑。取回C:/WINDOWS/TEST.EXE
(2)GetFileTitle();取文件全名:TEST.EXE
(3)GetFileName();取回TEST
(4)GetFileExt();取擴展名EXE

[2]打開文件
CFile file("C:/HELLO.TXT",CFile::modeRead);//只讀方式打開
//CFile::modeRead可改爲 CFile::modeWrite(只寫),
//CFile::modeReadWrite(讀寫),CFile::modeCreate(新建)
例子:
{
CFile file;
file.Open("C:/HELLO.TXT",CFile::modeCreate|Cfile::modeWrite);
.
.
.
}

[3]移動文件指針
file.Seek(100,CFile::begin);///從文件頭開始往下移動100字節
file.Seek(-50,CFile::end);///從文件末尾往上移動50字節
file.Seek(-30,CFile::current);///從當前位置往上移動30字節
file.SeekToBegin();///移到文件頭
file.SeekToEnd();///移到文件尾

[4]讀寫文件
讀文件:
char buffer[1000];
file.Read(buffer,1000);
寫文件:
CString string("自強不息");
file.Write(string,8);

[5]關閉文件
file.Close();
提供一個關於調試多線程程序的方法:

1、對一條特定的線程進行調試
   Visual C++調試器支持多線的情況,如果你在許多線程都調用的函數中
   設置一個斷點,每當一個線程遭遇到此斷點,調試器就會在線程之間循環切換
   有個方法可以避開這個問題,就是掛起所有線程,除了你感興趣的那條(要調試
   的那條),在調試器中打開[Debug]菜單並選擇[Thread]你就可以獲得一個線程對
   話框,在這裏你可以掛起所有的線程,把你要調試的線程留下來,單獨調試他

2、運轉記錄
   就是讓程序的關鍵部分顯示出其發生的活動的一種方法!
   就是在程序的關鍵部位(某一時刻你想知道他的狀態)加上一些輸出語句,比如
   printf   TRACE  等等,可以將信息輸出到屏幕,也可以重定向到文件中,不要
   用一些控件比如ListBox,因爲ListBox也是一個窗口,在他的內部有自己的消息
   循環,向ListBox中輸出調試信息的時候,會引起不必要的線程切換(從當前
   線程切換到ListBox的消息循環)非常耗時!這對多線程這種對時間很敏感的程序
   來說有可能會影響運行的結果!
   在GUI程序中也是可以擁有console窗口的,由於console窗口由系統的設備驅動
   程序負責,即使你的程序當掉或在調試器中停止console窗口仍有反應!

3、內存記號(Memory Trails)
   上面的兩種方法執行的時間都稍長,有可能影響到程序運行的結果,Memory Trail
   屬於一種比較低階的技術!
   是用Memory Trail的方法:
   你必須產生一個足夠大的全局緩衝區,以及指向該緩衝區的全局指針,例如:
   char gMemTrail[16384];
   char *pMemTrail = gMemTrail;
   當你想輸出某些東西到屏幕上或文件中時,你就寫個記號到MemTrail中
   例如:
   *pMemTrail++ = 'f';
   你的程序的每一個追蹤點都應該寫一個不同的記號,不論什麼時候你想要,或是
   程序當掉之後,你可以利用調試器看看 memory trail中的內容!

3、硬件調試寄存器
   只適用於Intel機器!
   這個俺就不多說了,基本上很少用!

 

VC常見入門問題總結(二)
不好意思,這次只先總結出兩條:(
1:爲何我的下拉列表框找不到添加的內容?
    VC如果不安裝補丁的話,下拉列表框剛剛從控件欄拖到設計的對話框中時,其下拉列表的高度很小,所以經常會出現看不到內容的情況,在對話框設計中,點下列表框右側的三角,然後再把下拉列表拖大即可。
2:爲何一個位圖在打印狀態下於屏幕大小比較顯得非常小?
    可以認爲位圖是由顏色點陣構成的,因此一般情況下,它只有橫向縱向的像素數的概念,而沒有橫向縱向的寬度高度具體值的概念,因此,位圖的顯示大小是由顯示位圖的設備的分辨率決定的。顯示器的像素點的大小比起打印機要大很多,所以會出現位圖打印以及打印預覽狀態下非常小的問題。解決的方式使用StretchBlt函數拉伸位圖,見下面的小程序:
/*
//打印或者在屏幕上畫位圖
//pDC 打印機或者屏幕dc指針
iLogPixelX
iLogPixelY
屏幕DC的GetDeviceCaps(LOGPIXELSX)值,其中
iLogPixelX = DC.GetDeviceCaps ( LOGPIXELSX ) ;
iLogPixelY = DC.GetDeviceCaps ( LOGPIXELSY ) ;
iResBMPID BMP資源ID
*/
void DrawBMP (CDC * pDC, int iLogPixelX,int iLogPixelY,int iResBMPID)
{
CDC MemDC; // 內存設備環境指針,在視的整個存在過程都將存在
CBitmap Bitmap;
CRect Source, Dest; // 記錄源位圖尺寸和最終顯示尺寸
BITMAP bm;
if(MemDC.GetSafeHdc ( ) == NULL)
{
Bitmap.LoadBitmap ( iResBMPID ) ;
MemDC.CreateCompatibleDC ( pDC ) ;
MemDC.SelectObject( &Bitmap ) ;
Bitmap.GetObject ( sizeof ( bm ), &bm ) ;
Source.top = 0 ;
Source.left = 0 ;
Source.right= bm.bmWidth ;
Source.bottom = bm.bmHeight ;
Dest  =  Source ;
}
pDC->DPtoLP (& Dest ) ;
if ( pDC -> IsPrinting ( ) )
{
Dest.left = ( int ) ( Dest.left * ( (double)pDC->GetDeviceCaps ( LOGPIXELSX ) ) / iLogPixelX ) ;
Dest.right = ( int ) ( Dest.right * ( ( double ) pDC -> GetDeviceCaps ( LOGPIXELSX ) ) / iLogPixelX ) ;
Dest.top = ( int ) ( Dest.top * ( ( double ) pDC -> GetDeviceCaps ( LOGPIXELSY ) ) / iLogPixelY ) ;
Dest.bottom =( int ) ( Dest.bottom * ( ( double ) pDC -> GetDeviceCaps ( LOGPIXELSY ) ) / iLogPixelY ) ;
}
pDC -> StretchBlt ( Dest.left , Dest.top, Dest.right, Dest.bottom,
&MemDC, Source.left, Source.top, Source.right,Source.bottom, SRCCOPY ) ;
Bitmap.DeleteObject( ) ;
MemDC.DeleteDC( ) ;
return ;
}

 

我也將自己在實際編程中的經驗寫一下:
1、我在用VC操作ACCESS數據庫的時候,發現了一個現象,大家如果用過ACCESS的話,都知道ACCESS數據可以導出爲其他格式的文件,但是在導出爲TXT文件的時候,就容易丟失精度,當初是一個LONG類型的數據,導出後,被自動截斷,只保留了兩位精度,而我根據提取出來的數據畫圖,結果小小的誤差,差點被矇騙過去,呵呵

2、還有就是在使用指針的時候要注意,判斷指針是否是合法地址不能通過判斷地址來斷定,因爲非法地址可能是0xccccc  或者是0x000000 
虛擬按鍵的總結:以下是偶的總結,還有比如標點稱號及windows鍵的虛擬碼希望大家補充:

功能鍵:ESC:VK_ESCAPE,TAB:VK_TAB,PageUp:VK_PRIOR,PageDown:VK_NEXT

              Insert:VK_INSERT,Home:VK_HOME,End:VK_END

              Alt:VK_ALT,Ctrl:VK_CONTROL,Shift:VK_SHIFT,Delete:VK_DELETE

              上,下,左,右:VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT

              F1,F2,F3...:VK_F1,VK_F2,VK_F3......

字母和數字:a,b,c   ....:'A','B','C',.....

                      1,2,3,....:'1','2','3',.....

小鍵盤:1,2,3,........:VK_NUMPAD1,VK_NUMPAD2,VK_NUMPAD3,......

              +,1:VK_ADD,VK_SUBTRACT
Alt:VK_ALT,
該本人認爲可能被系統保留,
又整理出一份:
符號常量     十六進制值   指定的鼠標或鍵盤按鍵
VK_LBUTTON     01     鼠標左鍵
VK_RBUTTON     02     鼠標右鍵
VK_CANCEL     03     Control-break   過程
VK_MBUTTON     04     鼠標中鍵
VK_BACK     08     BACKSPACE   鍵
VK_TAB       09     TAB   鍵
VK_CLEAR     0C     CLEAR   鍵
VK_RETURN     0D     ENTER   鍵
VK_SHIFT     10     SHIFT   鍵
VK_CONTROL     11     CTRL   鍵
VK_MENU     12     ALT   鍵
VK_PAUSE     13     PAUSE   鍵
VK_CAPITAL     14     CAPS   LOCK   鍵
VK_ESCAPE     1B     ESC   鍵
VK_SPACE     20     SPACEBAR
VK_PRIOR     21     PAGE   UP   鍵
VK_NEXT     22     PAGE   DOWN   鍵
VK_END       23     END   鍵
VK_HOME     24     HOME   鍵
VK_LEFT     25     LEFT   ARROW   鍵
VK_UP       26     UP   ARROW   鍵
VK_RIGHT     27     RIGHT   ARROW   鍵
VK_DOWN     28     DOWN   ARROW   鍵
VK_SELECT     29     SELECT   鍵
VK_EXECUTE     2B     EXECUTE   鍵
VK_SNAPSHOT     2C     PRINT   SCREEN鍵(用於Windows   3.0及以後版本)
VK_INSERT     2D     INS   鍵
VK_DELETE     2E     DEL   鍵
VK_HELP     2F     HELP   鍵
/////////////////////
對於非小鍵盤上的數字鍵和字母鍵,直接在單引號中加入該鍵就行.
比如:a鍵:'A'
          1鍵:'1'
/////////////////////////////////
VK_LWIN     5B     Left   Windows   鍵   (Microsoft自然鍵盤)
VK_RWIN     5C     Right   Windows   鍵   (Microsoft自然鍵盤)
VK_APPS     5D     Applications   鍵   (Microsoft自然鍵盤)
VK_NUMPAD0     60     數字小鍵盤上的   0   鍵
VK_NUMPAD1     61     數字小鍵盤上的   1   鍵
VK_NUMPAD2     62     數字小鍵盤上的   2   鍵
VK_NUMPAD3     63     數字小鍵盤上的   3   鍵
VK_NUMPAD4     64     數字小鍵盤上的   4   鍵
VK_NUMPAD5     65     數字小鍵盤上的   5   鍵
VK_NUMPAD6     66     數字小鍵盤上的   6   鍵
VK_NUMPAD7     67     數字小鍵盤上的   7   鍵
VK_NUMPAD8     68     數字小鍵盤上的   8   鍵
VK_NUMPAD9     69     數字小鍵盤上的   9   鍵
VK_MULTIPLY     6A     Multiply   鍵
VK_ADD       6B     Add   鍵
VK_SEPARATOR     6C     Separator   鍵
VK_SUBTRACT     6D     Subtract   鍵
VK_DECIMAL     6E     Decimal   鍵
VK_DIVIDE     6F     Divide   鍵
VK_F1     70     F1   鍵
VK_F2     71     F2   鍵
VK_F3     72     F3   鍵
VK_F4     73     F4   鍵
VK_F5     74     F5   鍵
VK_F6     75     F6   鍵
VK_F7     76     F7   鍵
VK_F8     77     F8   鍵
VK_F9     78     F9   鍵
VK_F10     79     F10   鍵
VK_F11     7A     F11   鍵
VK_F12     7B     F12   鍵
VK_F13     7C     F13   鍵
VK_F14     7D     F14   鍵
VK_F15     7E     F15   鍵
VK_F16     7F     F16   鍵
VK_F17     80H     F17   鍵
VK_F18     81H     F18   鍵
VK_F19     82H     F19   鍵
VK_F20     83H     F20   鍵
VK_F21     84H     F21   鍵
VK_F22     85H     F22   鍵
VK_F23     86H     F23   鍵
VK_F24     87H     F24   鍵
VK_NUMLOCK     90     NUM   LOCK   鍵
VK_SCROLL     91     SCROLL   LOCK   鍵
VK_ATTN     F6     Attn   鍵
VK_CRSEL     F7     CrSel   鍵
VK_EXSEL     F8     ExSel   鍵
VK_EREOF     F9     Erase   EOF   鍵
VK_PLAY     FA     Play   鍵
VK_ZOOM     FB     Zoom   鍵
VK_OEM_CLEAR     FE     Clear   鍵
舉例說明這些鍵的用法:
(一)響應單獨的按鍵:
先添加PreTranslateMessage()(響應WM_CHAR)也是同樣的效果,因爲本例只捕捉鍵盤)
BOOL   CMydilog::PreTranslateMessage(MSG*   pMsg)  
{
//   TODO:   Add   your   specialized   code   here   and/or   call   the   base   class
if   (pMsg->message   ==   WM_KEYDOWN)
{
                            if(pMsg->wParam=='M')//直接用上面的虛碼代替就可以響應所指鍵
MessageBox("hello");//如果按下M鍵彈出消息.比如想當按下小鍵盤1時
                                                                            //彈出就用VK_NUMPAD1代替'M'
                  }
return   CDialog::PreTranslateMessage(pMsg);
}

(二)組合鍵的用法:(本例響應Ctrl+X鍵)
BOOL   CMydilog::PreTranslateMessage(MSG*   pMsg)  
{
//   TODO:   Add   your   specialized   code   here   and/or   call   the   base   class

if   (pMsg->message   ==   WM_KEYDOWN)
{
switch   (pMsg->wParam)
{
case   VK_ESCAPE:
SetFocus   ();
return   TRUE;
case   'X':
if(::GetKeyState(VK_CONTROL)   <   0)//如果是Shift+X這裏就
                                                                                                                          //改成VK_SHIFT
MessageBox("hello");
return   TRUE;

}
}
return   CDialog::PreTranslateMessage(pMsg);
}

 

1:使用CString,要包含文件afx.h,比如在Win32  Console  Application中Alt+F7選擇Use  MFC  in  a  Static  Liberary,然後再添加#include  <afx.h  >就可以使用CString了。 

2:WCHAR  ch  =  L’中’;與CHAR  ch  =  ’中’;的區別是第一種使用UNICODE編碼,第二種方式一般不經常用到,比如: 

                 WCHAR  strA  [  2  ]  =  {  L'中'  ,  0  }  ;//打開VC的Options菜單,選中Debug選項卡中的Display  unicode  strings後,可以看到strA的值。 
                 WCHAR  strB  [  2  ]  =  {  '中'  ,  0  }  ; 
                 CString  strC  ; 
                 strC+  =  (  (  char  *  )  strB  )  [  1  ]  ; 
                 strC+  =  (  (  char  *  )  strB  )  [  0  ]  ;//strC==”中” 

3:CString的AllocSysString  (  )成員函數;可以方便的把一個字符串轉換成UNICODE形式。記得使用完該UNICODE字符串後要調用::SysFreeString()函數釋放字符串。 

4:  CString::AllocSysString  (  )或者::SysAllocString得到的字符串並不是普通的UNICODE字符串,它之前的四個字節會存放申請的字符串的長度: 

                 CString  strD  =  ”asdf”; 
                 BSTR  strD  =  strC.AllocSysString(  )  ; 
                 long  i  =*  (  (  long  *  )  strD  –  1  )  ;  //  i  ==  8;一個UNICDE字符的長度是2字節,所以strD的長度爲8個字節。 

4:UTF-8碼轉換爲一般的字符串: 

#include    "Windows.h" 
int  main(void) 

char  str  [  256  ]  =  {(  char  )0xE4,  (  char  )  0xBD,  (  char  )  0xA0,  (  char  )  0xE5  ,(  char)0xA5  ,(char)0xBD,  (char)0x61,  (char)0x62  ,(char)0x63,(char)0}  ;    //一段UTF-8編碼 
WCHAR*  strA; 
int  i=  MultiByteToWideChar  (  CP_UTF8  ,  0  ,(char*)  str  ,-1  ,NULL,0); 
strA  =  new  WCHAR[i]; 
MultiByteToWideChar  (  CP_UTF8  ,  0  ,(  char  *  )  str,  -1,  strA  ,  i); 
i=  WideCharToMultiByte(CP_ACP,0,strA,-1,NULL,0,NULL,NULL); 
char  *strB=new  char[i]; 
WideCharToMultiByte  (CP_ACP,0,strA,-1,strB,i,NULL,NULL); 
//strB即爲所求 
delete  []strA; 
delete  []strB; 
return  0; 

5:在轉換方面_bstr_t是最最靈活的,他提供了UNICODE到一般字符串的直接轉換: 

#include    <comdef.h  > 
                 _bstr_t  strA; 
                 char  *strB=  "中國人  "; 
                 strA=strB; 
                 WCHAR  *strC=strA; 
                 long  i  =*  (  (  long  *  )  strC  -  1  )  ;//  i  亦是字符串的字節長度 
                 char  *strD=strA; 
                 return  0; 

6:如何得到當前應用程序路徑?
char *str = new char[256];
::GetModuleFileName(NULL,str,MAX_PATH);
//str即爲所求
delete []str;
str=NULL;

CfileDlg這個系統對話框我們經常遇到,但他提供的多形式靈活的參數,不是很多人瞭解,通過靈活的運用參數,可以讓操作更靈活多變.

以下介紹CfileDlg的參數:

構造CFileDialogST對象。
可以傳送最常用的參數(parameters)到參數列表(argument list)。

//參數:
//        [IN]    bOpenFileDialog
//                設置成TRUE構造一個打開文件對話框,FALSE爲保存文件對話框。
//        [IN]    lpszDefExt
//                默認文件擴展名。
//                如果用戶用戶沒有在文件名編輯框中輸入文件擴展名,默認文件擴展名被自動附加到文件名上。如果設置爲空,不附加任何擴展名。
//        [IN]    lpszFileName
//                在文件名編輯框中顯示的初始文件名。如果爲NULL,不顯示任何初始文件名。
//        [IN]    dwFlags
//                用來定製對話框的一個或多個flags的組合。
//        [IN]    lpszFilter
//                一系列字符串對(pairs)用來設置文件過濾器,只有符合過濾條件的文件才能出現在文件列表框中。
//        [IN]    pParentWnd
//                指向文件對話框的父窗口,可以爲NULL。
//
CFileDialogST(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, DWORD dwFlags
CFileDialogST()
構造CFileDialogST對象。

必須自己初始化公有成員變量m_ofn and m_bOpenFileDialog後才能使用(這個對象)。

DoModal()
本函數顯示文件對話框,允許用戶進行選擇。m_ofn結構需要使用的域必須已經填寫(在構造函數中設置或直接存取該結構),而且公有變量m_bOpenFileDialog必須被設置(TRUE爲打開文件對話框,FALSE爲保存文件對話框)。

//返回值:
//        IDOK
//                The user has selected a filename.
//        IDCANCEL
//                The user has closed the dialog without selecting any filename.
//
int DoModal()

CString GetPathName() const
這個函數返回所選文件的全路徑。

//返回值:
//                包含文件全路徑的CString對象。
//
CString GetPathName() const

CString GetFileName() const
這個函數返回所選文件的文件名。

//返回值:
//                包含文件名的CString對象。
//
CString GetFileName() const

CString GetFileTitle() const
這個函數返回所選文件的標題。

//返回值:
//                包含文件標題的CString對象。
//
CString GetFileTitle() const

CString GetFileExt() const
這個函數返回所選文件的擴展名。

//返回值:
//                包含文件擴展名的CString對象。
//
CString GetFileExt() const

CString GetFileDir() const
這個函數返回所選文件的目錄(不包含驅動器)。

//返回值:
//                包含文件目錄(不包含驅動器)的CString對象。
//
CString GetFileDir() const

CString GetFileDrive() const
這個函數返回所選文件所在的驅動器。

//返回值:
//                包含文件所在的驅動器的CString對象。
//
CString GetFileDrive() const

POSITION GetStartPosition() const
這個函數返回文件列表的第一個文件位置。

//返回值:
//                一個用於迭代的POSITION。如果列表爲空,返回NULL。
//
POSITION GetStartPosition() const

CString GetNextPathName(POSITION& pos) const
這個函數返回下一個所選文件的全路徑。

//參數:
//        [IN]    pos
//                一個POSITION的引用,這個引用是上一次調用GetNextPathName或GetStartPosition返回的,如果到達列表結尾,返回NULL(用來控制迭代)。
//
//返回值:
//                包含文件全路徑的CString對象。
//
CString GetNextPathName(POSITION& pos) const

int SelectFolder(LPCTSTR lpszTitle = NULL, LPCTSTR lpszStartPath = NULL, UINT ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS, CWnd* pParentWnd = NULL)
這個函數允許用戶選擇一個文件夾。

//參數:
//        [IN]    lpszTitle
//                一個0結尾的字符串的地址,用來顯示在樹視圖控件的上方,作爲標題顯示。可以爲NULL。
//        [IN]    lpszStartPath
//                一個0結尾的字符串的地址,包含初始文件夾。 可以爲NULL。
//        [IN]    ulFlags
//                用來配置對話框的Flags。
//        [IN]    pParentWnd
//                指向對話框的父窗口,可以爲NULL。
//
//返回值:
//        IDOK
//                用戶選擇了一個文件夾,並按OK按鈕。調用GetSelectedFolder()可以返回選中的文件夾。
//        IDCANCEL
//                用戶沒有選擇任何文件夾,按CANCEL關閉窗口。
//
int SelectFolder(LPCTSTR lpszTitle, LPCTSTR lpszStartPath, UINT ulFlags, CWnd* pParentWnd)

CString GetSelectedFolder() const
這個函數返回用戶(使用SelectFolder)選擇的文件夾。

//返回值:
//                包含所選文件夾的CString對象。如果之前沒有調用SelectFolder,這個值可能爲空或者返回上一次選擇的文件夾。
//
CString GetSelectedFolder() const

CreateFile
打開文件
要對文件進行讀寫等操作,首先必須獲得文件句柄,通過該函數可以獲得文件句柄,該函數是通向文件世界的大門。

ReadFile
從文件中讀取字節信息。
在打開文件獲得了文件句柄之後,則可以通過該函數讀取數據。

WriteFile
向文件寫入字節信息。
同樣可以將文件句柄傳給該函數,從而實現對文件數據的寫入。

CloseHandle
關閉文件句柄。
打開門之後,自然要記得關上。

GetFileTime
獲取文件時間。
有三個文件時間可供獲取:創建時間、最後訪問時間、最後寫時間。
該函數同樣需要文件句柄作爲入口參數。

GetFileSize
獲取文件大小。
由於文件大小可以高達上數G(1G需要30位),因此一個32位的雙字節類型無法對其精確表達,因此返回碼錶示低32位,還有一個出口參數可以傳出高32位。
該函數同樣需要文件句柄作爲入口參數。

GetFileAttributes
獲取文件屬性。
可以獲取文件的存檔、只讀、系統、隱藏等屬性。
該函數只需一個文件路徑作爲參數。

SetFileAttributes
設置文件屬性。
能獲取,自然也應該能設置。
可以設置文件的存檔、只讀、系統、隱藏等屬性。
該函數只需一個文件路徑作爲參數。

GetFileInformationByHandle
獲取所有文件信息
該函數能夠獲取上面所有函數所能夠獲取的信息,如大小、屬性等,同時還包括一些其他地方無法獲取的信息,比如:文件卷標、索引和鏈接信息。
該函數需要文件句柄作爲入口參數。

GetFullPathName
獲取文件路徑
該函數獲取文件的完整路徑名。
需要提醒的是:只有當該文件在當前目錄下,結果才正確。
如果要得到真正的路徑。應該用GetModuleFileName函數。

CopyFile
複製文件
注意:只能複製文件,而不能複製目錄

MoveFileEx
移動文件
既可以移動文件,也可以移動目錄,但不能跨越盤符。(Window2000下設置移動標誌可以實現跨越盤符操作)

DeleteFile
刪除文件

GetTempPath
獲取Windows臨時目錄路徑

GetTempFileName
在Windows臨時目錄路徑下創建一個唯一的臨時文件

SetFilePoint
移動文件指針。
該函數用於對文件進行高級讀寫操作時。

LockFile
UnlockFile
LockFileEx
UnlockFileEx
以上四個函數用於對文件進行鎖定和解鎖。這樣可以實現文件的異步操作。可同時對文件的不同部分進行各自的操作。

LZOpenFile
打開壓縮文件以讀取

LZSeek
查找壓縮文件中的一個位置

LZRead
讀一個壓縮文件

LZClose
關閉一個壓縮文件

LZCopy
複製壓縮文件並在處理過程中展開

GetExpandedName
從壓縮文件中返回文件名稱。

以上六個函數爲32位API中的一個小擴展庫,文件壓縮擴展庫中的函數。文件壓縮可以用命令compress創建。

32位API提供一個稱爲文件映像的特性,它允許將文件直接映射爲一個應用的虛擬內存空間,這一技術可用於簡化和加速文件訪問。

CreateFileMapping
創建和命名映射

MapViewOfFile
把文件映射裝載如內存

UnmapViewOfFile
釋放視圖並把變化寫回文件

FlushViewOfFile
將視圖的變化刷新寫入磁盤
文件讀寫:

.
CStdioFile file("c://test.txt", CStdioFile::modeCreate|CStdioFile::modeWrite);
file.Close();

2.
CStdioFile file("c://test.txt", CStdioFile::modeReadWrite);
file.SeekToEnd();
//...
file.Close();

 

FILE* fp;
fp=fopen("d://111.txt","wb");
fseek(fp,0,SEEK_END);//移動到末尾
。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。
fclose(fp);

1.
CFile file("c://test.txt", CFile::modeCreate|CFile::modeWrite);
file.Close();

2.
CFile file("c://test.txt", CFile::modeReadWrite);
file.SeekToEnd();
//...
file.Close();

SaveLog(char* p)
{

  FILE *fd = fopen("c://zhang//xi//Log.txt","a+");
  if (fd == NULL)
  return ;
  fwrite(p,sizeof(char),strlen(p),fd);
  fwrite("/x0d/x0a",sizeof(char),2,fd);
  fclose(fd);
  return;
}
11:我應該怎樣防止MFC在窗口標題欄上添加文檔名?
     在PreCreateWindow函數中刪除FWS_ADDTOTITLE標誌的窗口樣式:
cs.style &= ~FWS_ADDTOTITLE ;
cs.style&=~WS_MAXIMIZEBOX;刪除最大化圖標。


12:我應該怎樣防止MFC在窗口標題欄上把文檔名預置成應用程序名?
     在PreCreateWindow函數中刪除FWS_PREFIXTITLE標誌的窗口樣式: 
     cs.style &= ~FWS_PREFIXTITLE; 
10:如果想把整個項目拷貝到軟盤,那些文件可以刪掉?
    除了項目文件夾中debug文件夾可以刪除外,.ncb,.clw,.opt 等文件也可以刪除,這些文件rebuilt all後可以重新生成。


cs.dwExStyle &= ~WS_EX_CLIENTEDGE;

/*
創建自定義消息程序步驟:
1:用ClassWard創建一個新project命名爲:MessageTest
2:此project選單文檔,取消Active X支持,取消打印支持,其它默認。finish.
3:在菜單中添加一個菜單“測試”其子菜單爲"test",並映射其執行方法:OnTest
4: 製造消息發送者:在資源中新增一個對話框,並用classward爲其創建類名爲
   TestDialog.然後在此對話框中加入一個Button,並用classward爲其映射執行函數
   OnButton1()。
5:在TestDialog.h文件中加入一行#define WM_MY_MESSAGE (WM_USER+100)
   用來定義自己的消息
6:在TestDialog.cpp文件中加入一行:#include "MainFrm.h"
7:爲對話框的Button按鈕加入發送消息代碼如下:
void TestDialog::OnButton1()
{
// TODO: Add your control notification handler code here
//獲取當前框架指針
CMainFrame *pMainFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
//獲取當前view指針
CView *pView=pMainFrame->GetActiveView();
if(pView!=NULL)
{
pView->PostMessage(WM_MY_MESSAGE,0,0);
}
}
以上是對於消息的發送者工作己完成
8:以下是對於消息接收者
在MessageTestView.h中也要定義:#define WM_MY_MESSAGE (WM_USER+100)
9:並在MessageTestView.h中定義消息映射函數如下:
protected:
//{{AFX_MSG(CMessageTestView)
afx_msg void OnTest();
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);   //此處爲自定義消息映射函數
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
10:在MessageTestView.cpp文件中,聲明消息響應函數如下:
BEGIN_MESSAGE_MAP(CMessageTestView, CView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage)  //自定義消息響應函數
ON_COMMAND(ID_TEST, OnTest)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
11:在MessageTestView.cpp文件中實現消息響應函數如下:
LRESULT CMessageTestView::OnMyMessage(WPARAM wParam,LPARAM lParam)
{
MessageBox("OnMyMessage!Receiver");
return 0;
}
12:將消息發送者與消息響應者聯繫起來。即:將對話框與菜單聯繫起來。
實現CMessageTestView的OnTest方法如下:
void CMessageTestView::OnTest()
{
// TODO: Add your command handler code here
TestDialog dlg;
dlg.DoModal();
}
13:以上完成了所有自定義消息過程
*/
////////////////////////////////////////////////////////////////
2:如何編寫一個程序在運行後馬上刪除自己。
/* 以下代碼在VC.net2002、BCB6.0、DevC++4.98環境下均編譯通過,並正常運行 */
/* Creamdog保留所有權力 */
#include <windows.h>
int main( int argc, char *argv[] )
{
HMODULE module = GetModuleHandle(0);
CHAR buf[MAX_PATH];
GetModuleFileName(module, buf, sizeof buf);
CloseHandle(HANDLE(4));
__asm
{
lea eax, buf;
push 0;
push 0;
push eax;
push ExitProcess;
push module;
push DeleteFile;
push UnmapViewOfFile;
ret;
}
return 0;
}
一. 奇怪的宏定義
  (1)  #define for if(0); else for 
按照c++標準,for中定義的變量的作用域應該只在for循環中有效,而VC卻不行,比如這樣定義是不對的
for(int i=0;i<90;i++)
{
...;
}

for(int i=0;i<90;i++)  //重複定義i變量
{
...;
}

如果加上標題的那句,那麼就可以了,就是讓i作用域侷限在else中.

(2)宏定義怪圈
#define  wait_event(wq,condition)  / 
do{  / 
if(condition)  / 
                           break;  / 
             __wait_event(wq,condition);  / 
}while(0) 


明明這句話只執行一次,爲什麼還還用do-while語句呢?

假設有這樣一個宏定義 
#define  macro(condition)  / 
if(condition)  dosomething(); 
現在在程序中這樣使用這個宏: 
if(temp) 
             macro(i); 
else 
             doanotherthing(); 
一切看起來很正常,但是仔細想想。這個宏會展開成: 
if(temp) 
             if(condition)  dosomething(); 
else   
             doanotherthing(); 
這時的else不是與第一個if語句匹配,而是錯誤的與第二個if語句進行了匹配,編譯通過了,但是運行的結果一定是錯誤的。 
爲了避免這個錯誤,我們使用do{….}while(0)  把它包裹起來,成爲一個獨立的語法單元,從而不會與上下文發生混淆。
同時因爲絕大多數的編譯器都能夠識別do{…}while(0)這種無用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低。

(3) #if(0)
........
#endif

這樣是爲了解釋掉某段程序,而不影響其中的/*...*/的作用,便於調試

而/*.....*/是不能嵌套的,編譯會出錯.

(4)用下面語句實現數據轉換。 i=(int)(f*100);
當f=11.40(米)時,i=1139(釐米);
當f=11.41(米)時,i=1140(釐米);
當f=12.32(米)時,i=1231(釐米);
當f=12.33(米)時,i=1232(釐米);
等等,很多數據的轉換存在着&ldquo;1誤差&rdquo;。
不過,大部分數據的轉換是沒有誤差的,
如當f=11.39(米)時,i=1139(釐米);
當f=12.31(米)時,i=1231(釐米)。
如果改用以下方法實現數據轉換,
&ldquo;1誤差&rdquo;一樣存在。
float ftemp;
ftemp=f*100;
i=(int)ftemp;
這裏,ftemp是一局部變量(函數內定義)
或全局變量(函數外定義)。把f*100改成f*100.0,
&ldquo;1誤差&rdquo;也存在。但是如果把ftemp
改成爲類的屬性變量(在類裏定義),


(5)a[i]和i[a]
在程序裏本應該用a[i],但i[a]竟然和a[i]輸出的結果一樣。爲什麼。今天把問題整理如下:
i[a]是標準語法。“[]”稱爲下標運算符,其語法爲:
postfix_expression [ expression ]
其中“postfix_expression”和“expression”之中必須有一個是指針類型(或數組),而另一個是整型。
例如下面的程序是完全合法的:
int a[]={0,1,2,3,4};
printf("%d/n",3[a]);
下標運算符參與的表達式在求解時僅僅是做一個變換而已,將“postfix_expression [ expression ]”
改寫爲“ * ( postfix_expression + expression ) ”,因此a[3]和3[a]分別改寫爲*(a+3)和*(3+a),
可見二者是完全等價的。但注意不要用i[a]這種形式,因爲它不符合日常習慣。
實驗代碼:
#include "stdafx.h"
#include "iostream.h"
int f();
int main(int argc, char* argv[])
{

       int a[20]={1,2,3,4,5,6,7,8,9};
       cout<<a[f()]<<endl;
       cout<<f()[a]<<endl;
       return 0;
}

int f()
{
return 4;
}

實驗結果:
4
4
Press any key to continue

(6)int x;x;

這兒是個關於宏的問題,我曾用過ATL的串轉換宏,包括W2A,開始有些東西我還不太明白。爲了使用這些宏,必須在函數的開始處用USES_CONVERSION來初始化某些局部變量。用就用吧,但是看看這個宏的定義,它有類似下面的代碼:

// 在atlconv.h文件中
#define USES_CONVERSION /
int _convert; _convert; /
UINT _acp = GetACP(); _acp; /
LPCWSTR _lpw; _lpw; /
LPCSTR _lpa; _lpa

爲什麼它們用“int x;x;”——這種後面跟着變量的聲明?

    很多人都碰到過這個令人困惑的問題,後來發現簡單的答案是:禁止編譯器的警告信息(warning)。如果單獨有一行代碼:
int x;
且從來沒有使用過x,那麼編譯器彙報錯“unreferenced local variable:x”,意思是未引用過的局部變量x,如果將警告信息的輸出
調到最大。爲了避免討厭的警告,USES_CONVERSION引用聲明的變量。

int x; // 聲明
x; // 使用這個變量

在C++之前的時代,程序員有時在C中用函數形參做同樣的事情來避免“unreferenced formal parameter”或其它的深奧費解的編譯錯誤。

void MyFunc(int x, char y)
{
x;
y;

}

當然,現在用下面的代碼可以更有效地完成同樣的事情:

// 參數 x 不是用
void MyFunc(int /* x */)
{

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章