Windows程序的基本结构(转)
生活随笔
收集整理的這篇文章主要介紹了
Windows程序的基本结构(转)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、概述
Windows程序具有相對(duì)固定的結(jié)構(gòu),對(duì)編寫者而言,不需要書寫整個(gè)過程,大部分過程由系統(tǒng)完成。
程序中只要按一定的格式填寫系統(tǒng)留給客戶的那一小部分。
所需要完成的有:
窗口類的定義、窗口的建立、消息函數(shù)的書寫、消息循環(huán)。
二、消息處理函數(shù)
Windows程序是事件驅(qū)動(dòng)的,對(duì)于一個(gè)窗口,它的大部分例行維護(hù)是由系統(tǒng)維護(hù)的。沒個(gè)窗口都有一個(gè)消息處理函數(shù)。
在消息處理函數(shù)中,對(duì)傳入的消息進(jìn)行處理。系統(tǒng)內(nèi)還有它自己的缺省消息處理函數(shù)。
客戶寫一個(gè)消息處理函數(shù),在窗口建立前,將消息處理函數(shù)與窗口關(guān)聯(lián)。這樣,每當(dāng)有消息產(chǎn)生時(shí),就會(huì)去調(diào)用這個(gè)消息處理函數(shù)。
通常情況下,客戶都不會(huì)處理全部的消息,而是只處理自己感興趣的消息,其他的,則送回到系統(tǒng)的缺省消息處理函數(shù)中去。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case ...
...
case ...
...
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
三、窗口的建立
客戶需要自己建立窗口,建立后會(huì)得到系統(tǒng)返回的窗口句柄(HWND),后繼的針對(duì)窗口的操作都針對(duì)句柄進(jìn)行。
1.注冊(cè)窗口類
建立窗口前,需要制定好這個(gè)窗口的相關(guān)屬性,最主要的就是將自己定義的消息處理函數(shù)與窗口關(guān)聯(lián),其他的屬性還包括:菜單、圖標(biāo)等等。
這個(gè)屬性指定步驟是通過指定"窗口類"來完成的。
對(duì)于自己建立的窗口,這個(gè)"窗口類"需要自己制定,也即自己填充一個(gè)WNDCLASS結(jié)構(gòu),然后向系統(tǒng)注冊(cè)。
對(duì)于一些特殊窗口,如按鈕等控件,他們的行為是系統(tǒng)制定好了的,所以不需要自己注冊(cè),直接使用對(duì)應(yīng)的“窗口類”名稱就行了。
2.建立窗口
建立窗口時(shí),注冊(cè)的"窗口類"名稱作為參數(shù)傳入。
這樣,當(dāng)有針對(duì)該窗口的消息時(shí),將調(diào)用“窗口類”中指定的消息處理函數(shù),在其中得到處理。
四、消息循環(huán)
系統(tǒng)會(huì)將針對(duì)這個(gè)程序的消息依次放到程序的“消息隊(duì)列”中,由程序自己依次取出消息,在分發(fā)到對(duì)應(yīng)的窗口中去。
因此,建立窗口后,將進(jìn)入一個(gè)循環(huán)。
在循環(huán)中,取出消息、派發(fā)消息,循環(huán)往復(fù),直到取得的消息是退出消息。
循環(huán)退出后,程序即結(jié)束。
#include "stdafx.h"
#include <windows.h>
//一、消息處理函數(shù)
//參數(shù):窗口句柄,消息,消息參數(shù),消息參數(shù)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//處理感興趣的消息
switch (message)
{
case WM_DESTROY:
//當(dāng)用戶關(guān)閉窗口,窗口銷毀,程序需結(jié)束,發(fā)退出消息,以退出消息循環(huán)
PostQuitMessage (0) ;
return 0 ;
}
//其他消息交給由系統(tǒng)提供的缺省處理函數(shù)
return ::DefWindowProc (hwnd, message, wParam, lParam) ;
} //二、應(yīng)用程序主函數(shù)
//參數(shù):實(shí)例句柄、前一個(gè)實(shí)例的句柄、命令行參數(shù)、窗口顯示方式
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
//1.注冊(cè)窗口類
static TCHAR szAppName[] = TEXT ("HelloWin") ; //窗口類名稱
//定制"窗口類"結(jié)構(gòu)
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ; //關(guān)聯(lián)消息處理函數(shù)
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ; //實(shí)例句柄
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; //圖標(biāo)
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; //光標(biāo)
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); //畫刷
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName; //類名稱
//注冊(cè)
if (!ReGISterClass (&wndclass))
{
MessageBox (NULL, TEXT ("RegisterClass Fail!"),
szAppName, MB_ICONERROR) ;
return 0 ;
} //建立窗口
HWND hwnd ;
hwnd = CreateWindow (szAppName, //窗口類名稱
TEXT ("The Hello Program"), //窗口標(biāo)題
WS_OVERLAPPEDWINDOW, //窗口風(fēng)格
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance, //實(shí)例句柄
NULL); ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
//消息循環(huán)
MSG msg ;
while (GetMessage (&msg, NULL, 0, 0)) //從消息隊(duì)列中取消息
{
TranslateMessage (&msg) ; //轉(zhuǎn)換消息
DispatchMessage (&msg) ; //派發(fā)消息
}
return msg.wParam ;
}?
在EasyWin.cpp文件中輸入以下源程序代碼。
//*******************************************************************
// 工程:easywin
// 文件:easywin.cpp
// 內(nèi)容:一個(gè)基本的Win32程序//******************************************************************* #include <Windows.h> #include <windowsx.h> //函數(shù)聲明 BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ); LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); //******************************************************************* //函數(shù):WinMain() //功能:Win32應(yīng)用程序入口函數(shù)。創(chuàng)建主窗口,處理消息循環(huán) //******************************************************************* int PASCAL WinMain( HINSTANCE hInstance, //當(dāng)前實(shí)例句柄 HINSTANCE hPrevInstance, //前一個(gè)實(shí)例句柄 LPSTR lpCmdLine, //命令行字符 int nCmdShow) //窗口顯示方式 { MSG msg; //創(chuàng)建主窗口 if ( !InitWindow( hInstance, nCmdShow ) ) return FALSE; //進(jìn)入消息循環(huán): //從該應(yīng)用程序的消息隊(duì)列中檢取消息,送到消息處理過程, //當(dāng)檢取到WM_QUIT消息時(shí),退出消息循環(huán)。 while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //程序結(jié)束 return msg.wParam; } //****************************************************************** //函數(shù):InitWindow() //功能:創(chuàng)建窗口。 //****************************************************************** static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ) { HWND hwnd; //窗口句柄 WNDCLASS wc; //窗口類結(jié)構(gòu) //填充窗口類結(jié)構(gòu) wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = (WNDPROC)WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWin"; //注冊(cè)窗口類 ReGISterClass( &wc ); //創(chuàng)建主窗口 hwnd = CreateWindow( "EasyWin", //窗口類名稱 "一個(gè)基本的Win32程序", //窗口標(biāo)題 WS_OVERLAPPEDWINDOW, //窗口風(fēng)格,定義為普通型 100, //窗口位置的x坐標(biāo) 100, //窗口位置的y坐標(biāo) 400, //窗口的寬度 300, //窗口的高度 NULL, //父窗口句柄 NULL, //菜單句柄 hInstance, //應(yīng)用程序?qū)嵗浔?NULL ); //窗口創(chuàng)建數(shù)據(jù)指針 if( !hwnd ) return FALSE; //顯示并更新窗口 ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); return TRUE; } //****************************************************************** //函數(shù):WinProc() //功能:處理主窗口消息 //****************************************************************** LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_KEYDOWN://擊鍵消息 switch( wParam ) { case VK_ESCAPE: MessageBox(hWnd,"ESC鍵按下了!","Keyboard",MB_OK); break; } break; case WM_RBUTTONDOWN://鼠標(biāo)消息 { MessageBox(hWnd,"鼠標(biāo)右鍵按下了!","Mouse",MB_OK); break; } case WM_PAINT://窗口重畫消息 { char hello[]="你好,我是EasyWin !"; HDC hdc; PAINTSTRUCT ps; hdc=BeginPaint( hWnd,&ps ); //取得設(shè)備環(huán)境句柄 SetTextColor(hdc, RGB(0,0,255)); //設(shè)置文字顏色 TextOut( hdc, 20, 10, hello, strlen(hello) );//輸出文字 EndPaint( hWnd, &ps ); //釋放資源 break; } case WM_DESTROY://退出消息 PostQuitMessage( 0 );//調(diào)用退出函數(shù) break; } //調(diào)用缺省消息處理過程 return DefWindowProc(hWnd, message, wParam, lParam); } 程序輸入完畢,即可編譯執(zhí)行。在窗口中擊鼠標(biāo)鍵或按ESC鍵時(shí),會(huì)彈出一個(gè)對(duì)話框以表示你的操作。 其實(shí),這個(gè)程序可以看成是所有Win32應(yīng)用程序的框架,在以后所有的程序中,你會(huì)發(fā)現(xiàn)它們都是在這個(gè)程序的基礎(chǔ)之上再添加代碼。
在EasyWin.cpp文件中輸入以下源程序代碼。
//*******************************************************************
// 工程:easywin
// 文件:easywin.cpp
// 內(nèi)容:一個(gè)基本的Win32程序//******************************************************************* #include <Windows.h> #include <windowsx.h> //函數(shù)聲明 BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ); LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); //******************************************************************* //函數(shù):WinMain() //功能:Win32應(yīng)用程序入口函數(shù)。創(chuàng)建主窗口,處理消息循環(huán) //******************************************************************* int PASCAL WinMain( HINSTANCE hInstance, //當(dāng)前實(shí)例句柄 HINSTANCE hPrevInstance, //前一個(gè)實(shí)例句柄 LPSTR lpCmdLine, //命令行字符 int nCmdShow) //窗口顯示方式 { MSG msg; //創(chuàng)建主窗口 if ( !InitWindow( hInstance, nCmdShow ) ) return FALSE; //進(jìn)入消息循環(huán): //從該應(yīng)用程序的消息隊(duì)列中檢取消息,送到消息處理過程, //當(dāng)檢取到WM_QUIT消息時(shí),退出消息循環(huán)。 while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //程序結(jié)束 return msg.wParam; } //****************************************************************** //函數(shù):InitWindow() //功能:創(chuàng)建窗口。 //****************************************************************** static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ) { HWND hwnd; //窗口句柄 WNDCLASS wc; //窗口類結(jié)構(gòu) //填充窗口類結(jié)構(gòu) wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = (WNDPROC)WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWin"; //注冊(cè)窗口類 ReGISterClass( &wc ); //創(chuàng)建主窗口 hwnd = CreateWindow( "EasyWin", //窗口類名稱 "一個(gè)基本的Win32程序", //窗口標(biāo)題 WS_OVERLAPPEDWINDOW, //窗口風(fēng)格,定義為普通型 100, //窗口位置的x坐標(biāo) 100, //窗口位置的y坐標(biāo) 400, //窗口的寬度 300, //窗口的高度 NULL, //父窗口句柄 NULL, //菜單句柄 hInstance, //應(yīng)用程序?qū)嵗浔?NULL ); //窗口創(chuàng)建數(shù)據(jù)指針 if( !hwnd ) return FALSE; //顯示并更新窗口 ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); return TRUE; } //****************************************************************** //函數(shù):WinProc() //功能:處理主窗口消息 //****************************************************************** LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_KEYDOWN://擊鍵消息 switch( wParam ) { case VK_ESCAPE: MessageBox(hWnd,"ESC鍵按下了!","Keyboard",MB_OK); break; } break; case WM_RBUTTONDOWN://鼠標(biāo)消息 { MessageBox(hWnd,"鼠標(biāo)右鍵按下了!","Mouse",MB_OK); break; } case WM_PAINT://窗口重畫消息 { char hello[]="你好,我是EasyWin !"; HDC hdc; PAINTSTRUCT ps; hdc=BeginPaint( hWnd,&ps ); //取得設(shè)備環(huán)境句柄 SetTextColor(hdc, RGB(0,0,255)); //設(shè)置文字顏色 TextOut( hdc, 20, 10, hello, strlen(hello) );//輸出文字 EndPaint( hWnd, &ps ); //釋放資源 break; } case WM_DESTROY://退出消息 PostQuitMessage( 0 );//調(diào)用退出函數(shù) break; } //調(diào)用缺省消息處理過程 return DefWindowProc(hWnd, message, wParam, lParam); } 程序輸入完畢,即可編譯執(zhí)行。在窗口中擊鼠標(biāo)鍵或按ESC鍵時(shí),會(huì)彈出一個(gè)對(duì)話框以表示你的操作。 其實(shí),這個(gè)程序可以看成是所有Win32應(yīng)用程序的框架,在以后所有的程序中,你會(huì)發(fā)現(xiàn)它們都是在這個(gè)程序的基礎(chǔ)之上再添加代碼。
注冊(cè)窗口類 一個(gè)應(yīng)用程序可以有許多窗口,但只有一個(gè)是主窗口,它是與該應(yīng)用程序的實(shí)例句柄唯一關(guān)聯(lián)的。上面的例程中,創(chuàng)建主窗口的函數(shù)是InitWindow()。 通常要對(duì)填充一個(gè)窗口類結(jié)構(gòu)WNDCLASS,然后調(diào)用ReGISterClass()對(duì)該窗口類進(jìn)行注冊(cè)。每個(gè)窗口都有一些基本的屬性,如窗口邊框、窗口標(biāo)題欄文字、窗口大小和位置、鼠標(biāo)、背景色、處理窗口消息函數(shù)的名稱等等。注冊(cè)的過程也就是將這些屬性告訴系統(tǒng),然后再調(diào)用CreateWindow()函數(shù)創(chuàng)建出窗口。這也就象你去裁縫店訂做一件衣服,先要告訴店老板你的身材尺寸、布料顏色、以及你想要的款式,然后他才能為你做出一件讓你滿意的衣服。 在VC的幫助中,可以看到WNDCLASS結(jié)構(gòu)是這樣定義的: typedef struct _WNDCLASS { UINT style; //窗口的風(fēng)格* WNDPROC lpfnWndProc; //指定窗口的消息處理函數(shù)的遠(yuǎn)指針* int cbClsExtra; //指定分配給窗口類結(jié)構(gòu)之后的額外字節(jié)數(shù)* int cbWndExtra; //指定分配給窗口實(shí)例之后的額外字節(jié)數(shù) HANDLE hInstance; //指定窗口過程所對(duì)應(yīng)的實(shí)例句柄* HICON hIcon; //指定窗口的圖標(biāo) HCURSOR hCursor; //指定窗口的鼠標(biāo) HBRUSH hbrBackground; //指定窗口的背景畫刷 LPCTSTR lpszMenuName; //窗口的菜單資源名稱 LPCTSTR lpszClassName; //該窗口類的名稱* } WNDCLASS; 在Win95和WinNT的具有新界面特性的系統(tǒng)中,為了支持新的窗口界面特性,還有一種擴(kuò)展的窗口類型WNDCLASSEX,它的定義如下: typedef struct _WNDCLASSEX { UINT cbSize; //指定WNDCLASSEX結(jié)構(gòu)的大小 UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; //窗口的小圖標(biāo) } WNDCLASSEX; WNDCLASS和WNDCLASSEX這兩個(gè)結(jié)構(gòu)基本上是一致的,只是WNDCLASSEX結(jié)構(gòu)中多了cbSize和hIconSm這兩個(gè)成員。WNDCLASS結(jié)構(gòu)的各成員中,其注釋后打了星號(hào)的表示該項(xiàng)應(yīng)特別注意。 WNDCLASS結(jié)構(gòu)的第一個(gè)成員style表示窗口類的風(fēng)格,它往往是由一些基本的風(fēng)格通過位的“或”操作(操作符位“|”)組合而成。下表列出了一些常用的基本窗口風(fēng)格: 風(fēng)格 含義?
CS_HREDRAW 如果窗口客戶區(qū)寬度發(fā)生改變,重繪整個(gè)窗口?
CS_VREDRAW 如果窗口客戶區(qū)高度發(fā)生改變,重繪整個(gè)窗口
CS_DBLCLKS 能感受用戶在窗口中的雙擊消息?
CS_NOCLOSE 禁用系統(tǒng)菜單中的“關(guān)閉”命令?
CS_OWNDC 為該窗口類的各窗口分配各自獨(dú)立的設(shè)備環(huán)境?
CS_CLASSDC 為該窗口類的各窗口分配一個(gè)共享的設(shè)備環(huán)境?
CS_PARENTDC 指定子窗口繼承其父窗口的設(shè)備環(huán)境
CS_SAVEBITS 把被窗口遮掩的屏幕圖象部分作為位圖保存起來。當(dāng)該窗口被移動(dòng)時(shí),Windows使用被保存的位圖來重建屏幕圖象? 在EasyWin應(yīng)用程序中,是按如下方式對(duì)WNDCLASS結(jié)構(gòu)進(jìn)行填充和注冊(cè)的: wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = (WNDPROC)WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWin";? 可以看到,wc.style被設(shè)為CS_VREDRAW | CS_HREDRAW,表示只要窗口的高度或?qū)挾劝l(fā)生變化,都會(huì)重畫整個(gè)窗口。 第二個(gè)成員lpfnWndProc的值為(WNDPROC)WinProc。表明該窗口類的消息處理函數(shù)是WinProc()函數(shù)。這里,要指定窗口的消息處理函數(shù)的遠(yuǎn)指針,輸入消息處理函數(shù)的函數(shù)名稱即可,必要時(shí)應(yīng)該進(jìn)行強(qiáng)制類型轉(zhuǎn)換,將其轉(zhuǎn)換成WNDPROC型。 接下來的cbClsExtra和wc.cbWndExtra在大多數(shù)情況下都會(huì)設(shè)為0。 然后的hInstance成員,給它的值是由WinMain()傳來的應(yīng)用程序的實(shí)例句柄,表明該窗口與該實(shí)例是相關(guān)聯(lián)的。事實(shí)上,只要是注冊(cè)窗口類,該成員的值始終是該程序的實(shí)例句柄,你應(yīng)該象背書一樣記住它。 下面的hIcon,是讓你給這個(gè)窗口指定一個(gè)圖標(biāo),調(diào)用 LoadIcon( hInstance, IDI_APPLICATION ),可以調(diào)用系統(tǒng)內(nèi)部預(yù)先定義好的標(biāo)志符為IDC_APPLICATION的圖標(biāo)作為該窗口的圖標(biāo)。 同樣,調(diào)用LoadCursor( NULL, IDC_ARROW )為該窗口調(diào)用系統(tǒng)內(nèi)部預(yù)先定義好的箭頭型鼠標(biāo)。 hbrBackground成員用來定義窗口的背景畫刷顏色,也就是該窗口的背景色。調(diào)用GetStockObject(WHITE_BRUSH)可以獲得系統(tǒng)內(nèi)部預(yù)先定義好的白色畫刷作為窗口的背景色。 上面的LoadIcon()、LoadCursor()、GetStockObject()都是Windows的API函數(shù),它們的用法可以參看VC的幫助,這里就不多介紹了。 lpszMenuName成員的值我們給它NULL,表示該窗口將沒有菜單。如果你想讓你的窗口擁有菜單,就把lpszMenuName成員賦值為標(biāo)志菜單資源的字符串。 WNDCLASS結(jié)構(gòu)的最后一個(gè)成員lpszClassName是讓你給這個(gè)窗口類起一個(gè)唯一的名稱,因?yàn)閃indows操作系統(tǒng)中有許許多多的窗口類,必須用一個(gè)獨(dú)一無二的名稱來代表它們。通常,你可以用你的程序名來命名這個(gè)窗口類的名稱。這個(gè)名稱將在創(chuàng)建窗口的CreateWindow()函數(shù)中用到。 填充完畢后,對(duì)于WNDCLASS結(jié)構(gòu),調(diào)用RegisterClass()函數(shù)進(jìn)行注冊(cè);對(duì)于WNDCLASSEX結(jié)構(gòu),調(diào)用RegisterClassEx()函數(shù)進(jìn)行注冊(cè),它們的原型分別如下: ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );? 該函數(shù)如調(diào)用成功,則返回一個(gè)非0值,表明系統(tǒng)中已經(jīng)注冊(cè)了一個(gè)名為EasyWin的窗口類。如果失敗,則返回0。 創(chuàng)建窗口 當(dāng)窗口類注冊(cè)完畢之后,并不會(huì)有窗口顯示出來,因?yàn)樽?cè)的過程僅僅是為創(chuàng)建窗口所做的準(zhǔn)備工作。實(shí)際創(chuàng)建一個(gè)窗口的是通過調(diào)用CreateWindow()函數(shù)完成的。窗口類中已經(jīng)預(yù)先定義了窗口的一般屬性,而CreateWindow()中的參數(shù)可以進(jìn)一步指定一個(gè)窗口的更具體的屬性,在EasyWin程序中,是如下調(diào)用CreateWindow()函數(shù)來創(chuàng)建窗口的: hwnd = CreateWindow( "EasyWin", //創(chuàng)建窗口所用的窗口類的名稱* "一個(gè)基本的Win32程序", //窗口標(biāo)題 WS_OVERLAPPEDWINDOW, //窗口風(fēng)格,定義為普通型* 100, //窗口位置的x坐標(biāo) 100, //窗口位置的y坐標(biāo) 400, //窗口的寬度 300, //窗口的高度 NULL, //父窗口句柄 NULL, //菜單句柄 hInstance, //應(yīng)用程序?qū)嵗浔? NULL ); //一般都為NULL CreateWindow()函數(shù)的參數(shù)的含義在上面的注釋中已有介紹,注釋后打了星號(hào)標(biāo)記的參數(shù)應(yīng)該著重注意,其它的參數(shù)都很簡單,不多做介紹,可參看VC的幫助。 第一個(gè)參數(shù)是創(chuàng)建該窗口所使用的窗口類的名稱,注意這個(gè)名稱應(yīng)與前面所注冊(cè)的窗口類的名稱一致。 第三個(gè)參數(shù)為創(chuàng)建的窗口的風(fēng)格,下表列出了常用的窗口風(fēng)格: 風(fēng)格 含義?
WS_OVERLAPPEDWINDOW 創(chuàng)建一個(gè)層疊式窗口,有邊框、標(biāo)題欄、系統(tǒng)菜單、最大最小化按鈕,是以下幾種風(fēng)格的集合:WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, WS_MAXIMIZEBOX?
WS_POPUPWINDOW? 創(chuàng)建一個(gè)彈出式窗口,是以下幾種風(fēng)格的集合: WS_BORDER,WS_POPUP,WS_SYSMENU。WS_CAPTION與WS_POPUPWINDOW風(fēng)格必須一起使用才能使窗口菜單可見?
WS_OVERLAPPED 創(chuàng)建一個(gè)層疊式窗口,它有標(biāo)題欄和邊框,與WS_TILED風(fēng)格一樣?
WS_POPUP 該窗口為彈出式窗口,不能與WS_CHILD同時(shí)使用?
WS_BORDER 窗口有單線邊框?
WS_CAPTION 窗口有標(biāo)題欄?
WS_CHILD 該窗口為子窗口,不能與WS_POPUP同時(shí)使用?
WS_DISABLED? 該窗口為無效,即對(duì)用戶操作不產(chǎn)生任何反應(yīng)
WS_HSCROLL 窗口有水平滾動(dòng)條?
WS_ICONIC 窗口初始化為最小化?
WS_MAXIMIZE? 窗口初始化為最大化?
WS_MAXIMIZEBOX? 窗口有最大化按鈕?
WS_MINIMIZE 與WS_MAXIMIZE一樣?
WS_MINIMIZEBOX 窗口有最小化按鈕?
WS_SIZEBOX 邊框可進(jìn)行大小控制的窗口?
WS_SYSMENU 創(chuàng)建一個(gè)有系統(tǒng)菜單的窗口,必須與WS_CAPTION風(fēng)格同時(shí)使用?
WS_THICKFRAME 創(chuàng)建一個(gè)大小可控制的窗口,與WS_SIZEBOX 風(fēng)格一樣.
WS_TILED 創(chuàng)建一個(gè)層疊式窗口,有標(biāo)題欄?
WS_VISIBLE 窗口為可見?
WS_VSCROLL 窗口有垂直滾動(dòng)條?
程序中使用了WS_OVERLAPPEDWINDOW標(biāo)志,它是創(chuàng)建一個(gè)普通窗口常用的標(biāo)志。而在DirectX編程中,我們常用的是WS_POPUP,用這個(gè)標(biāo)志創(chuàng)建的窗口沒有標(biāo)題欄和系統(tǒng)菜單,如果設(shè)定窗口為最大化,客戶區(qū)可以占滿整個(gè)屏幕,以滿足DirectX編程的需要。 CreateWindow()函數(shù)后面的參數(shù)中,仍用到了該應(yīng)用程序的實(shí)例句柄hInstance。 如果窗口創(chuàng)建成功,返回值是新窗口的句柄,否則返回NULL。 顯示和更新窗口 窗口創(chuàng)建后,并不會(huì)在屏幕上顯示出來,要真正把窗口顯示在屏幕上,還得使用ShowWindow()函數(shù),其原型如下: BOOL ShowWindow( HWND hWnd, int nCmdShow );? 參數(shù)hWnd指定要顯示得窗口的句柄,nCmdShow表示窗口的顯示方式,這里指定為從WinMain()函數(shù)的nCmdShow所傳遞而來的值。 由于ShowWindow()函數(shù)的執(zhí)行優(yōu)先級(jí)不高,所以當(dāng)系統(tǒng)正忙著執(zhí)行其它的任務(wù)時(shí),窗口不會(huì)立即顯示出來,此時(shí),調(diào)用UpdateWindow()函數(shù)以可以立即顯示窗口。其函數(shù)原型如下: BOOL UpdateWindow( HWND hWnd );? 消息循環(huán) 在Win32編程中,消息循環(huán)是相當(dāng)重要的一個(gè)概念,看似很難,但是使用起來卻是非常簡單。在WinMain()函數(shù)中,調(diào)用InitWindow()函數(shù)成功的創(chuàng)建了應(yīng)用程序主窗口之后,就要啟動(dòng)消息循環(huán),其代碼如下: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
? Windows應(yīng)用程序可以接收以各種形式輸入的信息,這包括鍵盤、鼠標(biāo)動(dòng)作 、記時(shí)器產(chǎn)生的消息,也可以是其它應(yīng)用程序發(fā)來的消息等等。Windows系統(tǒng)自動(dòng)監(jiān)控所有的輸入設(shè)備,并將其消息放入該應(yīng)用程序的消息隊(duì)列中。 GetMessage()函數(shù)則是用來從應(yīng)用程序的消息隊(duì)列中按照先進(jìn)先出的原則將這些消息一個(gè)個(gè)的取出來,放進(jìn)一個(gè)MSG結(jié)構(gòu)中去。GetMessage()函數(shù)原型如下: BOOL GetMessage( LPMSG lpMsg, //指向一個(gè)MSG結(jié)構(gòu)的指針,用來保存消息 HWND hWnd, //指定哪個(gè)窗口的消息將被獲取 UINT wMsgFilterMin, //指定獲取的主消息值的最小值 UINT wMsgFilterMax //指定獲取的主消息值的最大值 );
? GetMessage()將獲取的消息復(fù)制到一個(gè)MSG結(jié)構(gòu)中。如果隊(duì)列中沒有任何消息,GetMessage()函數(shù)將一直空閑直到隊(duì)列中又有消息時(shí)再返回。如果隊(duì)列中已有消息,它將取出一個(gè)后返回。MSG結(jié)構(gòu)包含了一條Windows消息的完整信息,其定義如下: typedef struct tagMSG { HWND hwnd; //接收消息的窗口句柄 UINT message; //主消息值 WPARAM wParam; //副消息值,其具體含義依賴于主消息值 LPARAM lParam; //副消息值,其具體含義依賴于主消息值 DWORD time; //消息被投遞的時(shí)間 POINT pt; //鼠標(biāo)的位置 } MSG; 該結(jié)構(gòu)中的主消息表明了消息的類型,例如是鍵盤消息還是鼠標(biāo)消息等,副消息的含義則依賴于主消息值,例如:如果主消息是鍵盤消息,那么副消息中則存儲(chǔ)了是鍵盤的哪個(gè)具體鍵的信息。 GetMessage()函數(shù)還可以過濾消息,它的第二個(gè)參數(shù)是用來指定從哪個(gè)窗口的消息隊(duì)列中獲取消息,其它窗口的消息將被過濾掉。如果該參數(shù)為NULL,則GetMessage()從該應(yīng)用程序線程的所有窗口的消息隊(duì)列中獲取消息。 第三個(gè)和第四個(gè)參數(shù)是用來過濾MSG結(jié)構(gòu)中主消息值的,主消息值在wMsgFilterMin和wMsgFilterMax之外的消息將被過濾掉。如果這兩個(gè)參數(shù)為0,則表示接收所有消息。 當(dāng)且僅當(dāng)GetMessage()函數(shù)在獲取到WM_QUIT消息后,將返回0值,于是程序退出消息循環(huán)。 TranslateMessage()函數(shù)的作用是把虛擬鍵消息轉(zhuǎn)換到字符消息,以滿足鍵盤輸入的需要。DispatchMessage()函數(shù)所完成的工作是把當(dāng)前的消息發(fā)送到對(duì)應(yīng)的窗口過程中去。 開啟消息循環(huán)其實(shí)是很簡單的一個(gè)步驟,幾乎所有的程序都是按照EasyWin的這個(gè)方法。你完全不必去深究這些函數(shù)的作用,只是簡單的照抄就可以了。
消息處理函數(shù) 消息處理函數(shù)又叫窗口過程,在這個(gè)函數(shù)中,不同的消息將用switch語句分配到不同的處理程序中去。Windows的消息處理函數(shù)都有一個(gè)確定的樣式,即這種函數(shù)的參數(shù)個(gè)數(shù)和類型以及其返回值的類型都有明確的規(guī)定。在VC的說明書中,消息處理函數(shù)的原型是這樣定義的: LRESULT CALLBACK WindowProc( HWND hwnd, //接收消息窗口的句柄 UINT uMsg, //主消息值 WPARAM wParam, //副消息值 LPARAM lParam //副消息值 );? 如果你的程序中還有其它的消息處理函數(shù),也都必須按照上面的這個(gè)樣式來定義,但函數(shù)名稱可以隨便取。EasyWin中的WinProc()函數(shù)就是這樣一個(gè)典型的消息處理函數(shù)。 消息處理函數(shù)的四個(gè)參數(shù)是由GetMessage()函數(shù)從消息隊(duì)列中獲得MSG結(jié)構(gòu),然后分解后得到的。第二個(gè)參數(shù)uMsg和MSG結(jié)構(gòu)中的message值是一致的,代表了主消息值。程序中用switch語句來將不同類型的消息分配到不同的處理程序中去。 WinProc()函數(shù)明確的處理了4個(gè)消息,分別是WM_KEYDOWN(擊鍵消息)、WM_RBUTTONDOWN(鼠標(biāo)右鍵按下消息)、WM_PAINT(窗口重畫消息)、WM_DESTROY(銷毀窗口消息)。 值得注意的是,應(yīng)用程序發(fā)送到窗口的消息遠(yuǎn)遠(yuǎn)不止以上這幾條,象WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等這樣頻頻使用的消息就有幾十條。為了減輕編程的負(fù)擔(dān),Windows的API提供了DefWindowProc()函數(shù)來處理這些最常用的消息,調(diào)用了這個(gè)函數(shù)后,這些消息將按照系統(tǒng)默認(rèn)的方式得到處理。 因此,在switch_case語句中,只須明確的處理那些有必要進(jìn)行特別響應(yīng)的消息,把其余的消息交給DefWindowProc()函數(shù)來處理,是一種明智的選擇,也是你必須做的一件事。
結(jié)束消息循環(huán) 當(dāng)用戶按Alt+F4或單擊窗口右上角的退出按鈕,系統(tǒng)就向應(yīng)用程序發(fā)送一條WM_DESTROY的消息。在處理此消息時(shí),調(diào)用了PostQuitMessage()函數(shù),該函數(shù)會(huì)給窗口的消息隊(duì)列中發(fā)送一條WM_QUIT的消息。在消息循環(huán)中,GetMessage()函數(shù)一旦檢索到這條消息,就會(huì)返回FALSE,從而結(jié)束消息循環(huán),隨后,程序也結(jié)束。 小結(jié) 本章介紹的是Win32編程的基礎(chǔ)知識(shí),在進(jìn)行DirectX編程之前,掌握它們是十分必要的。 通過本文的學(xué)習(xí),你應(yīng)該學(xué)到以下知識(shí): 如何創(chuàng)建一個(gè)Win32應(yīng)用程序工程 用ReGISterClass()函數(shù)注冊(cè)一個(gè)窗口類,再立即調(diào)用CreateWindow()函數(shù)創(chuàng)建一個(gè)窗口的實(shí)例 設(shè)置窗口的類型以及將一個(gè)消息處理函數(shù)與窗口聯(lián)系上 用一固定的模式開啟消息循環(huán) 了解消息處理函數(shù)的定義規(guī)則,如何自己定義一個(gè)窗口消息處理函數(shù) 在消息處理函數(shù)中,最后必須調(diào)用DefWindowProc()函數(shù)以處理那些缺省的消息 調(diào)用PostQuitMessage()函數(shù)以結(jié)束消息循環(huán) 轉(zhuǎn)自(http://blog.chinaunix.net/uid-9563036-id-352229.html)
Windows程序具有相對(duì)固定的結(jié)構(gòu),對(duì)編寫者而言,不需要書寫整個(gè)過程,大部分過程由系統(tǒng)完成。
程序中只要按一定的格式填寫系統(tǒng)留給客戶的那一小部分。
所需要完成的有:
窗口類的定義、窗口的建立、消息函數(shù)的書寫、消息循環(huán)。
二、消息處理函數(shù)
Windows程序是事件驅(qū)動(dòng)的,對(duì)于一個(gè)窗口,它的大部分例行維護(hù)是由系統(tǒng)維護(hù)的。沒個(gè)窗口都有一個(gè)消息處理函數(shù)。
在消息處理函數(shù)中,對(duì)傳入的消息進(jìn)行處理。系統(tǒng)內(nèi)還有它自己的缺省消息處理函數(shù)。
客戶寫一個(gè)消息處理函數(shù),在窗口建立前,將消息處理函數(shù)與窗口關(guān)聯(lián)。這樣,每當(dāng)有消息產(chǎn)生時(shí),就會(huì)去調(diào)用這個(gè)消息處理函數(shù)。
通常情況下,客戶都不會(huì)處理全部的消息,而是只處理自己感興趣的消息,其他的,則送回到系統(tǒng)的缺省消息處理函數(shù)中去。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case ...
...
case ...
...
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
三、窗口的建立
客戶需要自己建立窗口,建立后會(huì)得到系統(tǒng)返回的窗口句柄(HWND),后繼的針對(duì)窗口的操作都針對(duì)句柄進(jìn)行。
1.注冊(cè)窗口類
建立窗口前,需要制定好這個(gè)窗口的相關(guān)屬性,最主要的就是將自己定義的消息處理函數(shù)與窗口關(guān)聯(lián),其他的屬性還包括:菜單、圖標(biāo)等等。
這個(gè)屬性指定步驟是通過指定"窗口類"來完成的。
對(duì)于自己建立的窗口,這個(gè)"窗口類"需要自己制定,也即自己填充一個(gè)WNDCLASS結(jié)構(gòu),然后向系統(tǒng)注冊(cè)。
對(duì)于一些特殊窗口,如按鈕等控件,他們的行為是系統(tǒng)制定好了的,所以不需要自己注冊(cè),直接使用對(duì)應(yīng)的“窗口類”名稱就行了。
2.建立窗口
建立窗口時(shí),注冊(cè)的"窗口類"名稱作為參數(shù)傳入。
這樣,當(dāng)有針對(duì)該窗口的消息時(shí),將調(diào)用“窗口類”中指定的消息處理函數(shù),在其中得到處理。
四、消息循環(huán)
系統(tǒng)會(huì)將針對(duì)這個(gè)程序的消息依次放到程序的“消息隊(duì)列”中,由程序自己依次取出消息,在分發(fā)到對(duì)應(yīng)的窗口中去。
因此,建立窗口后,將進(jìn)入一個(gè)循環(huán)。
在循環(huán)中,取出消息、派發(fā)消息,循環(huán)往復(fù),直到取得的消息是退出消息。
循環(huán)退出后,程序即結(jié)束。
#include "stdafx.h"
#include <windows.h>
//一、消息處理函數(shù)
//參數(shù):窗口句柄,消息,消息參數(shù),消息參數(shù)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//處理感興趣的消息
switch (message)
{
case WM_DESTROY:
//當(dāng)用戶關(guān)閉窗口,窗口銷毀,程序需結(jié)束,發(fā)退出消息,以退出消息循環(huán)
PostQuitMessage (0) ;
return 0 ;
}
//其他消息交給由系統(tǒng)提供的缺省處理函數(shù)
return ::DefWindowProc (hwnd, message, wParam, lParam) ;
} //二、應(yīng)用程序主函數(shù)
//參數(shù):實(shí)例句柄、前一個(gè)實(shí)例的句柄、命令行參數(shù)、窗口顯示方式
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
//1.注冊(cè)窗口類
static TCHAR szAppName[] = TEXT ("HelloWin") ; //窗口類名稱
//定制"窗口類"結(jié)構(gòu)
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ; //關(guān)聯(lián)消息處理函數(shù)
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ; //實(shí)例句柄
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; //圖標(biāo)
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; //光標(biāo)
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); //畫刷
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName; //類名稱
//注冊(cè)
if (!ReGISterClass (&wndclass))
{
MessageBox (NULL, TEXT ("RegisterClass Fail!"),
szAppName, MB_ICONERROR) ;
return 0 ;
} //建立窗口
HWND hwnd ;
hwnd = CreateWindow (szAppName, //窗口類名稱
TEXT ("The Hello Program"), //窗口標(biāo)題
WS_OVERLAPPEDWINDOW, //窗口風(fēng)格
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance, //實(shí)例句柄
NULL); ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
//消息循環(huán)
MSG msg ;
while (GetMessage (&msg, NULL, 0, 0)) //從消息隊(duì)列中取消息
{
TranslateMessage (&msg) ; //轉(zhuǎn)換消息
DispatchMessage (&msg) ; //派發(fā)消息
}
return msg.wParam ;
}?
在EasyWin.cpp文件中輸入以下源程序代碼。
//*******************************************************************
// 工程:easywin
// 文件:easywin.cpp
// 內(nèi)容:一個(gè)基本的Win32程序//******************************************************************* #include <Windows.h> #include <windowsx.h> //函數(shù)聲明 BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ); LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); //******************************************************************* //函數(shù):WinMain() //功能:Win32應(yīng)用程序入口函數(shù)。創(chuàng)建主窗口,處理消息循環(huán) //******************************************************************* int PASCAL WinMain( HINSTANCE hInstance, //當(dāng)前實(shí)例句柄 HINSTANCE hPrevInstance, //前一個(gè)實(shí)例句柄 LPSTR lpCmdLine, //命令行字符 int nCmdShow) //窗口顯示方式 { MSG msg; //創(chuàng)建主窗口 if ( !InitWindow( hInstance, nCmdShow ) ) return FALSE; //進(jìn)入消息循環(huán): //從該應(yīng)用程序的消息隊(duì)列中檢取消息,送到消息處理過程, //當(dāng)檢取到WM_QUIT消息時(shí),退出消息循環(huán)。 while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //程序結(jié)束 return msg.wParam; } //****************************************************************** //函數(shù):InitWindow() //功能:創(chuàng)建窗口。 //****************************************************************** static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ) { HWND hwnd; //窗口句柄 WNDCLASS wc; //窗口類結(jié)構(gòu) //填充窗口類結(jié)構(gòu) wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = (WNDPROC)WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWin"; //注冊(cè)窗口類 ReGISterClass( &wc ); //創(chuàng)建主窗口 hwnd = CreateWindow( "EasyWin", //窗口類名稱 "一個(gè)基本的Win32程序", //窗口標(biāo)題 WS_OVERLAPPEDWINDOW, //窗口風(fēng)格,定義為普通型 100, //窗口位置的x坐標(biāo) 100, //窗口位置的y坐標(biāo) 400, //窗口的寬度 300, //窗口的高度 NULL, //父窗口句柄 NULL, //菜單句柄 hInstance, //應(yīng)用程序?qū)嵗浔?NULL ); //窗口創(chuàng)建數(shù)據(jù)指針 if( !hwnd ) return FALSE; //顯示并更新窗口 ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); return TRUE; } //****************************************************************** //函數(shù):WinProc() //功能:處理主窗口消息 //****************************************************************** LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_KEYDOWN://擊鍵消息 switch( wParam ) { case VK_ESCAPE: MessageBox(hWnd,"ESC鍵按下了!","Keyboard",MB_OK); break; } break; case WM_RBUTTONDOWN://鼠標(biāo)消息 { MessageBox(hWnd,"鼠標(biāo)右鍵按下了!","Mouse",MB_OK); break; } case WM_PAINT://窗口重畫消息 { char hello[]="你好,我是EasyWin !"; HDC hdc; PAINTSTRUCT ps; hdc=BeginPaint( hWnd,&ps ); //取得設(shè)備環(huán)境句柄 SetTextColor(hdc, RGB(0,0,255)); //設(shè)置文字顏色 TextOut( hdc, 20, 10, hello, strlen(hello) );//輸出文字 EndPaint( hWnd, &ps ); //釋放資源 break; } case WM_DESTROY://退出消息 PostQuitMessage( 0 );//調(diào)用退出函數(shù) break; } //調(diào)用缺省消息處理過程 return DefWindowProc(hWnd, message, wParam, lParam); } 程序輸入完畢,即可編譯執(zhí)行。在窗口中擊鼠標(biāo)鍵或按ESC鍵時(shí),會(huì)彈出一個(gè)對(duì)話框以表示你的操作。 其實(shí),這個(gè)程序可以看成是所有Win32應(yīng)用程序的框架,在以后所有的程序中,你會(huì)發(fā)現(xiàn)它們都是在這個(gè)程序的基礎(chǔ)之上再添加代碼。
在EasyWin.cpp文件中輸入以下源程序代碼。
//*******************************************************************
// 工程:easywin
// 文件:easywin.cpp
// 內(nèi)容:一個(gè)基本的Win32程序//******************************************************************* #include <Windows.h> #include <windowsx.h> //函數(shù)聲明 BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ); LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); //******************************************************************* //函數(shù):WinMain() //功能:Win32應(yīng)用程序入口函數(shù)。創(chuàng)建主窗口,處理消息循環(huán) //******************************************************************* int PASCAL WinMain( HINSTANCE hInstance, //當(dāng)前實(shí)例句柄 HINSTANCE hPrevInstance, //前一個(gè)實(shí)例句柄 LPSTR lpCmdLine, //命令行字符 int nCmdShow) //窗口顯示方式 { MSG msg; //創(chuàng)建主窗口 if ( !InitWindow( hInstance, nCmdShow ) ) return FALSE; //進(jìn)入消息循環(huán): //從該應(yīng)用程序的消息隊(duì)列中檢取消息,送到消息處理過程, //當(dāng)檢取到WM_QUIT消息時(shí),退出消息循環(huán)。 while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //程序結(jié)束 return msg.wParam; } //****************************************************************** //函數(shù):InitWindow() //功能:創(chuàng)建窗口。 //****************************************************************** static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow ) { HWND hwnd; //窗口句柄 WNDCLASS wc; //窗口類結(jié)構(gòu) //填充窗口類結(jié)構(gòu) wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = (WNDPROC)WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWin"; //注冊(cè)窗口類 ReGISterClass( &wc ); //創(chuàng)建主窗口 hwnd = CreateWindow( "EasyWin", //窗口類名稱 "一個(gè)基本的Win32程序", //窗口標(biāo)題 WS_OVERLAPPEDWINDOW, //窗口風(fēng)格,定義為普通型 100, //窗口位置的x坐標(biāo) 100, //窗口位置的y坐標(biāo) 400, //窗口的寬度 300, //窗口的高度 NULL, //父窗口句柄 NULL, //菜單句柄 hInstance, //應(yīng)用程序?qū)嵗浔?NULL ); //窗口創(chuàng)建數(shù)據(jù)指針 if( !hwnd ) return FALSE; //顯示并更新窗口 ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); return TRUE; } //****************************************************************** //函數(shù):WinProc() //功能:處理主窗口消息 //****************************************************************** LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_KEYDOWN://擊鍵消息 switch( wParam ) { case VK_ESCAPE: MessageBox(hWnd,"ESC鍵按下了!","Keyboard",MB_OK); break; } break; case WM_RBUTTONDOWN://鼠標(biāo)消息 { MessageBox(hWnd,"鼠標(biāo)右鍵按下了!","Mouse",MB_OK); break; } case WM_PAINT://窗口重畫消息 { char hello[]="你好,我是EasyWin !"; HDC hdc; PAINTSTRUCT ps; hdc=BeginPaint( hWnd,&ps ); //取得設(shè)備環(huán)境句柄 SetTextColor(hdc, RGB(0,0,255)); //設(shè)置文字顏色 TextOut( hdc, 20, 10, hello, strlen(hello) );//輸出文字 EndPaint( hWnd, &ps ); //釋放資源 break; } case WM_DESTROY://退出消息 PostQuitMessage( 0 );//調(diào)用退出函數(shù) break; } //調(diào)用缺省消息處理過程 return DefWindowProc(hWnd, message, wParam, lParam); } 程序輸入完畢,即可編譯執(zhí)行。在窗口中擊鼠標(biāo)鍵或按ESC鍵時(shí),會(huì)彈出一個(gè)對(duì)話框以表示你的操作。 其實(shí),這個(gè)程序可以看成是所有Win32應(yīng)用程序的框架,在以后所有的程序中,你會(huì)發(fā)現(xiàn)它們都是在這個(gè)程序的基礎(chǔ)之上再添加代碼。
注冊(cè)窗口類 一個(gè)應(yīng)用程序可以有許多窗口,但只有一個(gè)是主窗口,它是與該應(yīng)用程序的實(shí)例句柄唯一關(guān)聯(lián)的。上面的例程中,創(chuàng)建主窗口的函數(shù)是InitWindow()。 通常要對(duì)填充一個(gè)窗口類結(jié)構(gòu)WNDCLASS,然后調(diào)用ReGISterClass()對(duì)該窗口類進(jìn)行注冊(cè)。每個(gè)窗口都有一些基本的屬性,如窗口邊框、窗口標(biāo)題欄文字、窗口大小和位置、鼠標(biāo)、背景色、處理窗口消息函數(shù)的名稱等等。注冊(cè)的過程也就是將這些屬性告訴系統(tǒng),然后再調(diào)用CreateWindow()函數(shù)創(chuàng)建出窗口。這也就象你去裁縫店訂做一件衣服,先要告訴店老板你的身材尺寸、布料顏色、以及你想要的款式,然后他才能為你做出一件讓你滿意的衣服。 在VC的幫助中,可以看到WNDCLASS結(jié)構(gòu)是這樣定義的: typedef struct _WNDCLASS { UINT style; //窗口的風(fēng)格* WNDPROC lpfnWndProc; //指定窗口的消息處理函數(shù)的遠(yuǎn)指針* int cbClsExtra; //指定分配給窗口類結(jié)構(gòu)之后的額外字節(jié)數(shù)* int cbWndExtra; //指定分配給窗口實(shí)例之后的額外字節(jié)數(shù) HANDLE hInstance; //指定窗口過程所對(duì)應(yīng)的實(shí)例句柄* HICON hIcon; //指定窗口的圖標(biāo) HCURSOR hCursor; //指定窗口的鼠標(biāo) HBRUSH hbrBackground; //指定窗口的背景畫刷 LPCTSTR lpszMenuName; //窗口的菜單資源名稱 LPCTSTR lpszClassName; //該窗口類的名稱* } WNDCLASS; 在Win95和WinNT的具有新界面特性的系統(tǒng)中,為了支持新的窗口界面特性,還有一種擴(kuò)展的窗口類型WNDCLASSEX,它的定義如下: typedef struct _WNDCLASSEX { UINT cbSize; //指定WNDCLASSEX結(jié)構(gòu)的大小 UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; //窗口的小圖標(biāo) } WNDCLASSEX; WNDCLASS和WNDCLASSEX這兩個(gè)結(jié)構(gòu)基本上是一致的,只是WNDCLASSEX結(jié)構(gòu)中多了cbSize和hIconSm這兩個(gè)成員。WNDCLASS結(jié)構(gòu)的各成員中,其注釋后打了星號(hào)的表示該項(xiàng)應(yīng)特別注意。 WNDCLASS結(jié)構(gòu)的第一個(gè)成員style表示窗口類的風(fēng)格,它往往是由一些基本的風(fēng)格通過位的“或”操作(操作符位“|”)組合而成。下表列出了一些常用的基本窗口風(fēng)格: 風(fēng)格 含義?
CS_HREDRAW 如果窗口客戶區(qū)寬度發(fā)生改變,重繪整個(gè)窗口?
CS_VREDRAW 如果窗口客戶區(qū)高度發(fā)生改變,重繪整個(gè)窗口
CS_DBLCLKS 能感受用戶在窗口中的雙擊消息?
CS_NOCLOSE 禁用系統(tǒng)菜單中的“關(guān)閉”命令?
CS_OWNDC 為該窗口類的各窗口分配各自獨(dú)立的設(shè)備環(huán)境?
CS_CLASSDC 為該窗口類的各窗口分配一個(gè)共享的設(shè)備環(huán)境?
CS_PARENTDC 指定子窗口繼承其父窗口的設(shè)備環(huán)境
CS_SAVEBITS 把被窗口遮掩的屏幕圖象部分作為位圖保存起來。當(dāng)該窗口被移動(dòng)時(shí),Windows使用被保存的位圖來重建屏幕圖象? 在EasyWin應(yīng)用程序中,是按如下方式對(duì)WNDCLASS結(jié)構(gòu)進(jìn)行填充和注冊(cè)的: wc.style = CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = (WNDPROC)WinProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWin";? 可以看到,wc.style被設(shè)為CS_VREDRAW | CS_HREDRAW,表示只要窗口的高度或?qū)挾劝l(fā)生變化,都會(huì)重畫整個(gè)窗口。 第二個(gè)成員lpfnWndProc的值為(WNDPROC)WinProc。表明該窗口類的消息處理函數(shù)是WinProc()函數(shù)。這里,要指定窗口的消息處理函數(shù)的遠(yuǎn)指針,輸入消息處理函數(shù)的函數(shù)名稱即可,必要時(shí)應(yīng)該進(jìn)行強(qiáng)制類型轉(zhuǎn)換,將其轉(zhuǎn)換成WNDPROC型。 接下來的cbClsExtra和wc.cbWndExtra在大多數(shù)情況下都會(huì)設(shè)為0。 然后的hInstance成員,給它的值是由WinMain()傳來的應(yīng)用程序的實(shí)例句柄,表明該窗口與該實(shí)例是相關(guān)聯(lián)的。事實(shí)上,只要是注冊(cè)窗口類,該成員的值始終是該程序的實(shí)例句柄,你應(yīng)該象背書一樣記住它。 下面的hIcon,是讓你給這個(gè)窗口指定一個(gè)圖標(biāo),調(diào)用 LoadIcon( hInstance, IDI_APPLICATION ),可以調(diào)用系統(tǒng)內(nèi)部預(yù)先定義好的標(biāo)志符為IDC_APPLICATION的圖標(biāo)作為該窗口的圖標(biāo)。 同樣,調(diào)用LoadCursor( NULL, IDC_ARROW )為該窗口調(diào)用系統(tǒng)內(nèi)部預(yù)先定義好的箭頭型鼠標(biāo)。 hbrBackground成員用來定義窗口的背景畫刷顏色,也就是該窗口的背景色。調(diào)用GetStockObject(WHITE_BRUSH)可以獲得系統(tǒng)內(nèi)部預(yù)先定義好的白色畫刷作為窗口的背景色。 上面的LoadIcon()、LoadCursor()、GetStockObject()都是Windows的API函數(shù),它們的用法可以參看VC的幫助,這里就不多介紹了。 lpszMenuName成員的值我們給它NULL,表示該窗口將沒有菜單。如果你想讓你的窗口擁有菜單,就把lpszMenuName成員賦值為標(biāo)志菜單資源的字符串。 WNDCLASS結(jié)構(gòu)的最后一個(gè)成員lpszClassName是讓你給這個(gè)窗口類起一個(gè)唯一的名稱,因?yàn)閃indows操作系統(tǒng)中有許許多多的窗口類,必須用一個(gè)獨(dú)一無二的名稱來代表它們。通常,你可以用你的程序名來命名這個(gè)窗口類的名稱。這個(gè)名稱將在創(chuàng)建窗口的CreateWindow()函數(shù)中用到。 填充完畢后,對(duì)于WNDCLASS結(jié)構(gòu),調(diào)用RegisterClass()函數(shù)進(jìn)行注冊(cè);對(duì)于WNDCLASSEX結(jié)構(gòu),調(diào)用RegisterClassEx()函數(shù)進(jìn)行注冊(cè),它們的原型分別如下: ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );? 該函數(shù)如調(diào)用成功,則返回一個(gè)非0值,表明系統(tǒng)中已經(jīng)注冊(cè)了一個(gè)名為EasyWin的窗口類。如果失敗,則返回0。 創(chuàng)建窗口 當(dāng)窗口類注冊(cè)完畢之后,并不會(huì)有窗口顯示出來,因?yàn)樽?cè)的過程僅僅是為創(chuàng)建窗口所做的準(zhǔn)備工作。實(shí)際創(chuàng)建一個(gè)窗口的是通過調(diào)用CreateWindow()函數(shù)完成的。窗口類中已經(jīng)預(yù)先定義了窗口的一般屬性,而CreateWindow()中的參數(shù)可以進(jìn)一步指定一個(gè)窗口的更具體的屬性,在EasyWin程序中,是如下調(diào)用CreateWindow()函數(shù)來創(chuàng)建窗口的: hwnd = CreateWindow( "EasyWin", //創(chuàng)建窗口所用的窗口類的名稱* "一個(gè)基本的Win32程序", //窗口標(biāo)題 WS_OVERLAPPEDWINDOW, //窗口風(fēng)格,定義為普通型* 100, //窗口位置的x坐標(biāo) 100, //窗口位置的y坐標(biāo) 400, //窗口的寬度 300, //窗口的高度 NULL, //父窗口句柄 NULL, //菜單句柄 hInstance, //應(yīng)用程序?qū)嵗浔? NULL ); //一般都為NULL CreateWindow()函數(shù)的參數(shù)的含義在上面的注釋中已有介紹,注釋后打了星號(hào)標(biāo)記的參數(shù)應(yīng)該著重注意,其它的參數(shù)都很簡單,不多做介紹,可參看VC的幫助。 第一個(gè)參數(shù)是創(chuàng)建該窗口所使用的窗口類的名稱,注意這個(gè)名稱應(yīng)與前面所注冊(cè)的窗口類的名稱一致。 第三個(gè)參數(shù)為創(chuàng)建的窗口的風(fēng)格,下表列出了常用的窗口風(fēng)格: 風(fēng)格 含義?
WS_OVERLAPPEDWINDOW 創(chuàng)建一個(gè)層疊式窗口,有邊框、標(biāo)題欄、系統(tǒng)菜單、最大最小化按鈕,是以下幾種風(fēng)格的集合:WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, WS_MAXIMIZEBOX?
WS_POPUPWINDOW? 創(chuàng)建一個(gè)彈出式窗口,是以下幾種風(fēng)格的集合: WS_BORDER,WS_POPUP,WS_SYSMENU。WS_CAPTION與WS_POPUPWINDOW風(fēng)格必須一起使用才能使窗口菜單可見?
WS_OVERLAPPED 創(chuàng)建一個(gè)層疊式窗口,它有標(biāo)題欄和邊框,與WS_TILED風(fēng)格一樣?
WS_POPUP 該窗口為彈出式窗口,不能與WS_CHILD同時(shí)使用?
WS_BORDER 窗口有單線邊框?
WS_CAPTION 窗口有標(biāo)題欄?
WS_CHILD 該窗口為子窗口,不能與WS_POPUP同時(shí)使用?
WS_DISABLED? 該窗口為無效,即對(duì)用戶操作不產(chǎn)生任何反應(yīng)
WS_HSCROLL 窗口有水平滾動(dòng)條?
WS_ICONIC 窗口初始化為最小化?
WS_MAXIMIZE? 窗口初始化為最大化?
WS_MAXIMIZEBOX? 窗口有最大化按鈕?
WS_MINIMIZE 與WS_MAXIMIZE一樣?
WS_MINIMIZEBOX 窗口有最小化按鈕?
WS_SIZEBOX 邊框可進(jìn)行大小控制的窗口?
WS_SYSMENU 創(chuàng)建一個(gè)有系統(tǒng)菜單的窗口,必須與WS_CAPTION風(fēng)格同時(shí)使用?
WS_THICKFRAME 創(chuàng)建一個(gè)大小可控制的窗口,與WS_SIZEBOX 風(fēng)格一樣.
WS_TILED 創(chuàng)建一個(gè)層疊式窗口,有標(biāo)題欄?
WS_VISIBLE 窗口為可見?
WS_VSCROLL 窗口有垂直滾動(dòng)條?
程序中使用了WS_OVERLAPPEDWINDOW標(biāo)志,它是創(chuàng)建一個(gè)普通窗口常用的標(biāo)志。而在DirectX編程中,我們常用的是WS_POPUP,用這個(gè)標(biāo)志創(chuàng)建的窗口沒有標(biāo)題欄和系統(tǒng)菜單,如果設(shè)定窗口為最大化,客戶區(qū)可以占滿整個(gè)屏幕,以滿足DirectX編程的需要。 CreateWindow()函數(shù)后面的參數(shù)中,仍用到了該應(yīng)用程序的實(shí)例句柄hInstance。 如果窗口創(chuàng)建成功,返回值是新窗口的句柄,否則返回NULL。 顯示和更新窗口 窗口創(chuàng)建后,并不會(huì)在屏幕上顯示出來,要真正把窗口顯示在屏幕上,還得使用ShowWindow()函數(shù),其原型如下: BOOL ShowWindow( HWND hWnd, int nCmdShow );? 參數(shù)hWnd指定要顯示得窗口的句柄,nCmdShow表示窗口的顯示方式,這里指定為從WinMain()函數(shù)的nCmdShow所傳遞而來的值。 由于ShowWindow()函數(shù)的執(zhí)行優(yōu)先級(jí)不高,所以當(dāng)系統(tǒng)正忙著執(zhí)行其它的任務(wù)時(shí),窗口不會(huì)立即顯示出來,此時(shí),調(diào)用UpdateWindow()函數(shù)以可以立即顯示窗口。其函數(shù)原型如下: BOOL UpdateWindow( HWND hWnd );? 消息循環(huán) 在Win32編程中,消息循環(huán)是相當(dāng)重要的一個(gè)概念,看似很難,但是使用起來卻是非常簡單。在WinMain()函數(shù)中,調(diào)用InitWindow()函數(shù)成功的創(chuàng)建了應(yīng)用程序主窗口之后,就要啟動(dòng)消息循環(huán),其代碼如下: while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
? Windows應(yīng)用程序可以接收以各種形式輸入的信息,這包括鍵盤、鼠標(biāo)動(dòng)作 、記時(shí)器產(chǎn)生的消息,也可以是其它應(yīng)用程序發(fā)來的消息等等。Windows系統(tǒng)自動(dòng)監(jiān)控所有的輸入設(shè)備,并將其消息放入該應(yīng)用程序的消息隊(duì)列中。 GetMessage()函數(shù)則是用來從應(yīng)用程序的消息隊(duì)列中按照先進(jìn)先出的原則將這些消息一個(gè)個(gè)的取出來,放進(jìn)一個(gè)MSG結(jié)構(gòu)中去。GetMessage()函數(shù)原型如下: BOOL GetMessage( LPMSG lpMsg, //指向一個(gè)MSG結(jié)構(gòu)的指針,用來保存消息 HWND hWnd, //指定哪個(gè)窗口的消息將被獲取 UINT wMsgFilterMin, //指定獲取的主消息值的最小值 UINT wMsgFilterMax //指定獲取的主消息值的最大值 );
? GetMessage()將獲取的消息復(fù)制到一個(gè)MSG結(jié)構(gòu)中。如果隊(duì)列中沒有任何消息,GetMessage()函數(shù)將一直空閑直到隊(duì)列中又有消息時(shí)再返回。如果隊(duì)列中已有消息,它將取出一個(gè)后返回。MSG結(jié)構(gòu)包含了一條Windows消息的完整信息,其定義如下: typedef struct tagMSG { HWND hwnd; //接收消息的窗口句柄 UINT message; //主消息值 WPARAM wParam; //副消息值,其具體含義依賴于主消息值 LPARAM lParam; //副消息值,其具體含義依賴于主消息值 DWORD time; //消息被投遞的時(shí)間 POINT pt; //鼠標(biāo)的位置 } MSG; 該結(jié)構(gòu)中的主消息表明了消息的類型,例如是鍵盤消息還是鼠標(biāo)消息等,副消息的含義則依賴于主消息值,例如:如果主消息是鍵盤消息,那么副消息中則存儲(chǔ)了是鍵盤的哪個(gè)具體鍵的信息。 GetMessage()函數(shù)還可以過濾消息,它的第二個(gè)參數(shù)是用來指定從哪個(gè)窗口的消息隊(duì)列中獲取消息,其它窗口的消息將被過濾掉。如果該參數(shù)為NULL,則GetMessage()從該應(yīng)用程序線程的所有窗口的消息隊(duì)列中獲取消息。 第三個(gè)和第四個(gè)參數(shù)是用來過濾MSG結(jié)構(gòu)中主消息值的,主消息值在wMsgFilterMin和wMsgFilterMax之外的消息將被過濾掉。如果這兩個(gè)參數(shù)為0,則表示接收所有消息。 當(dāng)且僅當(dāng)GetMessage()函數(shù)在獲取到WM_QUIT消息后,將返回0值,于是程序退出消息循環(huán)。 TranslateMessage()函數(shù)的作用是把虛擬鍵消息轉(zhuǎn)換到字符消息,以滿足鍵盤輸入的需要。DispatchMessage()函數(shù)所完成的工作是把當(dāng)前的消息發(fā)送到對(duì)應(yīng)的窗口過程中去。 開啟消息循環(huán)其實(shí)是很簡單的一個(gè)步驟,幾乎所有的程序都是按照EasyWin的這個(gè)方法。你完全不必去深究這些函數(shù)的作用,只是簡單的照抄就可以了。
消息處理函數(shù) 消息處理函數(shù)又叫窗口過程,在這個(gè)函數(shù)中,不同的消息將用switch語句分配到不同的處理程序中去。Windows的消息處理函數(shù)都有一個(gè)確定的樣式,即這種函數(shù)的參數(shù)個(gè)數(shù)和類型以及其返回值的類型都有明確的規(guī)定。在VC的說明書中,消息處理函數(shù)的原型是這樣定義的: LRESULT CALLBACK WindowProc( HWND hwnd, //接收消息窗口的句柄 UINT uMsg, //主消息值 WPARAM wParam, //副消息值 LPARAM lParam //副消息值 );? 如果你的程序中還有其它的消息處理函數(shù),也都必須按照上面的這個(gè)樣式來定義,但函數(shù)名稱可以隨便取。EasyWin中的WinProc()函數(shù)就是這樣一個(gè)典型的消息處理函數(shù)。 消息處理函數(shù)的四個(gè)參數(shù)是由GetMessage()函數(shù)從消息隊(duì)列中獲得MSG結(jié)構(gòu),然后分解后得到的。第二個(gè)參數(shù)uMsg和MSG結(jié)構(gòu)中的message值是一致的,代表了主消息值。程序中用switch語句來將不同類型的消息分配到不同的處理程序中去。 WinProc()函數(shù)明確的處理了4個(gè)消息,分別是WM_KEYDOWN(擊鍵消息)、WM_RBUTTONDOWN(鼠標(biāo)右鍵按下消息)、WM_PAINT(窗口重畫消息)、WM_DESTROY(銷毀窗口消息)。 值得注意的是,應(yīng)用程序發(fā)送到窗口的消息遠(yuǎn)遠(yuǎn)不止以上這幾條,象WM_SIZE、WM_MINIMIZE、WM_CREATE、WM_MOVE等這樣頻頻使用的消息就有幾十條。為了減輕編程的負(fù)擔(dān),Windows的API提供了DefWindowProc()函數(shù)來處理這些最常用的消息,調(diào)用了這個(gè)函數(shù)后,這些消息將按照系統(tǒng)默認(rèn)的方式得到處理。 因此,在switch_case語句中,只須明確的處理那些有必要進(jìn)行特別響應(yīng)的消息,把其余的消息交給DefWindowProc()函數(shù)來處理,是一種明智的選擇,也是你必須做的一件事。
結(jié)束消息循環(huán) 當(dāng)用戶按Alt+F4或單擊窗口右上角的退出按鈕,系統(tǒng)就向應(yīng)用程序發(fā)送一條WM_DESTROY的消息。在處理此消息時(shí),調(diào)用了PostQuitMessage()函數(shù),該函數(shù)會(huì)給窗口的消息隊(duì)列中發(fā)送一條WM_QUIT的消息。在消息循環(huán)中,GetMessage()函數(shù)一旦檢索到這條消息,就會(huì)返回FALSE,從而結(jié)束消息循環(huán),隨后,程序也結(jié)束。 小結(jié) 本章介紹的是Win32編程的基礎(chǔ)知識(shí),在進(jìn)行DirectX編程之前,掌握它們是十分必要的。 通過本文的學(xué)習(xí),你應(yīng)該學(xué)到以下知識(shí): 如何創(chuàng)建一個(gè)Win32應(yīng)用程序工程 用ReGISterClass()函數(shù)注冊(cè)一個(gè)窗口類,再立即調(diào)用CreateWindow()函數(shù)創(chuàng)建一個(gè)窗口的實(shí)例 設(shè)置窗口的類型以及將一個(gè)消息處理函數(shù)與窗口聯(lián)系上 用一固定的模式開啟消息循環(huán) 了解消息處理函數(shù)的定義規(guī)則,如何自己定義一個(gè)窗口消息處理函數(shù) 在消息處理函數(shù)中,最后必須調(diào)用DefWindowProc()函數(shù)以處理那些缺省的消息 調(diào)用PostQuitMessage()函數(shù)以結(jié)束消息循環(huán) 轉(zhuǎn)自(http://blog.chinaunix.net/uid-9563036-id-352229.html)
轉(zhuǎn)載于:https://www.cnblogs.com/Fightingbirds/archive/2013/01/16/2862144.html
總結(jié)
以上是生活随笔為你收集整理的Windows程序的基本结构(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [置顶] 深入浅出Java
- 下一篇: 修改 SQL Server 服务器的 I