在這裏,我想談談自己學習MFC的一些體會。我是從1997年纔開始在Window下編寫程序的。在這之前,我編寫過一些DOS程序,包括一個簡單的全屏幕編輯器和一個帶函數的表達式解釋器,都是一些小的程序。Window 3.1流行後,我開始在它下面編寫程序。
從編寫DOS程序到編寫Window程序,需要從編程思想上作一個比較大的調整。在DOS下編寫程序,程序的總體流程完全由應用程序自己控制;但在 Window下,程序的總體流程是由操作系統控制的,這一點對在DOS下“胡作非爲”的DOS程序員而然,特別不習慣,思想上一時很難轉過彎來,總覺得操 作系統所控制的應用程序流程能夠滿足我們所提出的任意要求嗎?萬一某個應用程序所需要的流程同它相牴觸,那該怎麼樣?
但後來隨着學習的深入,我覺得這種擔心是完全多餘的,就我個人而然在還沒有碰到上面的問題。
另外一個轉變就是,在Window下,程序是由事件(或消息)驅動的,程序員在程序中主要是提供事件處理程序的代碼,然後由操作系統來調用這些代碼,從 程序員的角度看,就是操作系統在“回調”他或她所寫的代碼。這一點也很不習慣,因爲在DOS下,都是應用程序調用操作系統的代碼(API),現在一下反過 來了,角色變化了,受不了!不過,隨作編程量的增加,這一點也慢慢淡化了。
剛開始,我是用SDK編程的,使用了半年後,我受不了了, 太麻煩了,編寫一個簡單的顯示”hello, world!”的程序就得上百行代碼,再加上討厭的make文件和.def文件(那時我使用的是Borland C++ 3.1,而且也不知道有OWL這個東西)。後來聽人說,現在在Window下編寫C或C++程序用的都是MFC,MFC的功能很強大!於是,我到圖書館去 借了兩本講VC的書,照着書上的內容,折騰了一個禮拜。
說實在話,那一個禮拜是把我搞得最迷糊的一個禮拜,MFC把我給嚇壞了。是 的,用MFC編寫一個“hello, world!”程序只需自己編寫一行代碼,但我不知道我所編寫的那一行代碼是什麼時候執行的,我不知道MFC在背後幹了什麼。這些倒不是最主要的,更讓我 難以接受的是,我覺的我所有的編程行動都在MFC的控制之下,而且控制得更“死”了,我的思想鑽進上面所提到的“死衚衕”中去了。後來我想,如果那時候我 看了一些有關構件(Framework)的文章或書,我想,這個“死衚衕”對我而然,應該是不存在的。
其實,所有這些都是由於對 MFC不熟悉所造成的,MFC是一個框架(Framework)式類庫,框架式類庫同一般的類庫的不同之處在於,庫中的各個類之間是有聯繫的,它們是按照 框架所定義的模式去協作完成任務的。所以,要學習MFC,首先就要了解各個類之間是如何協作的以及它們的接口。
另外,我覺得,如果熟悉SDK的話,對理解MFC和使用MFC編寫程序是有很大幫助的,因此在後面的講解中,我會根據需要穿插一些SDK方面的知識,以助理解。
最後,必須具有一定的C++知識,完全不知道C++爲何物而去使用MFC,我實在難以想象其最後的結果,最好掌握C++的基本知識。
MFC應用程序的控制流程
一般的Window應用程序基本流程
WinMain()函數
任何一個應用程序都有一個入口函數,在Window下,程序的入口函數根據應用程序的類型,有兩種選擇:控制檯程序的入口函數是main(),一般的 Window界面程序的入口函數是WinMain()。這裏只探討同我們下面的討論有關的WinMain()函數。下面是該函數的原型:(Visuall C++中)
int APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
其中:
hInstance是標識當前進程的實例,它實際上是進程所佔據的地址空間的首地址,在很多Window API中,都要將它作爲一個參數傳進去,所以,應用程序一般都會將它保存在一個全局量中。
hPreInstance是應用程序前一個實例的實例句柄。這是16位Window的殘留物,在Win32應用程序中,這個參數始終爲NULL。所以,某些從16爲移植到32位的應用程序,如果使用了hPreInstance,就應該對代碼作相應的修改。
lpCmdLine是命令行參數,這同main()中的argv[]類似。
nCmdShow用來指明應用程序的主窗口的顯示方式(最大化顯示,最小化顯示,一般化顯示)。
一個實例
下面是一個顯示”Hello, world”的程序的代碼,它體現了一般的Window應用程序的基本流程。
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
file://註冊窗口類
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_HELLOWORLD);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_HELLOWORLD;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
RegisterClassEx(&wcex);
file://創建一個該類型的窗口
HWND hWnd;
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd) return FALSE;
file://一nCmdShow所指定的方式顯示窗口
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
file://啓動消息循環,將消息發送給相應的窗口函數
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
file://窗口函數
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
char* szHello = “Hello, world!”;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
上面程序的執行過程如下:
1、註冊一個窗口類
這是爲後面的創建窗口作準備,在使用CreateWindwo()和CreateWindowEx()創建窗口時,都必須提供一個標識窗口類的字符串。創建窗口類的主要意圖是向操作系統提供窗口處理函數。
2、創建窗口
啓動消息循環,分發並處理消息。
其中的關鍵部分是消息循環:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
調用GetMessage()從線程的消息隊列中取出一條消息,將消息翻譯後,再調用
DispatchMessage()將該消息分發至相應的窗口過程。(實際上DispatchMessage()是將該消息作爲參數調用對應的窗口的窗口函數,這就是分發的實質),在後面我們會詳細討論MFC的消息環同上面的消息環的區別。
進入MFC講壇的前言(一)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
Windows 2003下成功配置IIS+Php+Mysql+Zend Optimizer+GD庫+Phpmyadmin
yjz0065
2020-07-08 09:13:06
不要使用Windows的系統時間做數據排序
tyrone1979
2020-06-22 13:05:52
VS2005:declared deprecated warning問題
zeuskaaba
2020-06-16 13:54:36
VS2005 C++ 項目怎樣添加“依賴”、“庫目錄”和“包含目錄”
zeuskaaba
2020-06-16 13:54:36
DLL學習筆記(VS2005)(持續更新中.......)
zeuskaaba
2020-06-16 13:54:35
WPF應用ocx控件
SaylorLee
2020-06-13 04:27:22
配置×××服務器中的L2TP/IPSEC
85671778
2020-05-31 04:53:15
域控器發佈非msi文件方法
lht_8
2020-03-13 13:06:36
VB.NET可選參數調用方式解析
enenwenwen
2020-02-25 19:01:15
解讀PE/COFF文件格式
tyrone1979
2020-02-21 12:16:20
c# 異步編程(async + await + HttpClient)
SaylorLee
2020-02-21 04:33:16
全面剖析Windows平臺上運行企業級關鍵性任務
mapei
2019-11-17 13:26:17
秀一秀我的微軟MVP(最有價值專家)的大禮包和水晶獎盃!
小俠唐在飛
2019-07-19 15:15:42
windows操作系統自帶的TCP端口轉發命令
sfih
2019-07-19 14:03:06
DFS使用方法總結
jianyungao
2019-07-17 13:27:25