一、windows程序基礎
1. Windows程序的特點
1)用戶界面統一、友好
2)支持多任務:允許用戶同時運行多個應用程序(窗口)
3)獨立于設備的圖形操作
????????使用圖形設備接口( GDI, Graphics Device Interface )屏蔽了不同硬件設備的差異,提供了設備無關的圖形輸出能力
4)隊列化消息輸入,支持隊列特征的消息驅動模型
????????把從鍵盤、鼠標等輸入設備接收的輸入信息放入應用程序的隊列中; Windows操作系統管理隊列;應用程序需要輸入信息時,不讀硬件端口,只讀消息隊列。
5)事件驅動的程序設計
????????- Windows程序由事件的發展控制,允許程序的用戶用各種合理的順序來安排程序的流程。
6)資源共享
????????-各個應用程序共享系統提供的資源,包括設備上下文、畫刷、畫筆、字體、對話框、圖標、定時器、通信端口。
7)程序和資源分開
????????-菜單、對話框、位圖等可視對象被單獨分離出來加公的,全部資源定義都放在資源文件中(通常以.rc為后綴名)
8)支持應用程序間的數據交換
2. 一個簡單的Windows應用程序
#include <windows.h>
int WINAPI WinMain (HINSTANCE hInstance, HINS TANCE
hPrevInstance, LPSTR IpCmdLine, int nCmdShow)
{
MessageBox (NULL, "你好,我的Visual C++世界! ", "問候",MB_ OKCANCEL);
return 0 ;
}
運行結果:
3.事件及事件驅動
●Windows系統也叫事件驅動的系統。當用戶按下一個鍵、移動鼠標或單擊鼠標按鈕時,計算機通知Windows系統已經發生了一一個事件,以及事件的種類、發生的時間、發生的位置(如坐標值)。
●事件通常以下列三種方式產生:
????????-通過輸入設備,如鍵盤和鼠標;
????????-通過屏幕上可視的對象,如菜單、工具欄按鈕、動條和對話框上的控件;
????????-來自Windows內部,如當一個后面的窗口顯示到窗口前面時。
基于事件驅動的程序模型
?4.消息
????????●當Windows捕獲一 條事件后 ,它會編寫一條消息,將相關信息放入一個數據結構MSG中,然后將包含此數據結構的消息發給需要消息的程序。。
????????●消息處理是Windows應用程序的核心。
????????●消息是操作系統通知應用程序某件事情已經發生的一種方式。
????????●Windows消息是在Windows.h文件中用宏定義的常數。
????????●消息常數名常以WM_ 開頭,格式為WM_XX。
(1)Windows消息來源
Windows應用程序的消息來源于以下四種:
(1)輸入消息:鍵盤和鼠標的輸入。此類消息先放在系統消息隊列中,然后由Windows將它們送入應用程序消息隊列中,由應用程序來處理消息。
(2)控制消息:與Windows的控制對象,如列表框、復選框等進行雙向通信。這類消息一般不經過應用程序的消息隊列,而是直接發送到控制對象。
(3)系統消息:對程序化的事件或系統時鐘中斷作出的一些反應。
(4)用戶消息:程序員自己定義并在應用程序中主動發生的,一般由應用程序的某一部分內部處理。
????????VC+ +存在幾種系統定義的消息分類,不同的前綴符號經常用于識別不同的消息類,系統定義的消息宏前綴如下:
????????BM :按鈕控制消息
????????CB :組合框控制消息
????????DM :默認下壓式按鈕控制消息
????????EM :編輯控制消息
????????LB :列表框控制消息
????????SBM :滾動條控制消息
????????WM :窗口控制消息
(2)Windows消息數據結構
????????消息號:由事先定義好的消息名標識
????????字參數(wParam) :用于提供消息的附加信息
????????長字參數(IParam) :用于提供消息的附加信息
Windows消息的數據結構
typedef struct tagMSG?
{
HWND hwnd; //窗口句柄,為nul則可檢索所有駐留在消息隊交中的消息
UINT message; //消息值,由Windows h頭文件中的宏定義標識
WPARAM wParam; //包含有關消息的附加信息,不同消息其值不同
LPARAM IParam;
DWORD time; 1指定消息送至隊列的時間
POINT p:/消息發送時屏幕光標位置,POINT是一個結構體
}MSG;
? ? ? ? 注意:字參與長字參是作為消息的附加信息的,它與具體消息號的值有關;Windows中消息用結構體MSG表示;DWORD是32位無符號整型;
????????POINT是一個結構體:
typedef struct tagPOINT
{
LONGX;
LONG y;
}POINT,
二、消息隊列和API
1. Windows消息隊列?
????????●當產生某消息時,該消息進入消息隊列,操作系統根據消息提供的信息值決定由哪個應用程序來處理;
????????●應用程序按一定的方式查找應用程序中各個類的消息映射(一組宏,用來確定某個消息及相應的處理程序;的對應關系) ;
????????●找到處理程序后,由處理程序執行相應的操作。
????????●消息隊列是一一個系統定義的內存塊,用于臨時存儲消息,或把消息直接發給窗口函數。
????????●每個窗口維護自己的消息隊列,并從隊列中取出消息,利用窗口函數進行處理。
2. Windows程序常用消息
( 1 )標準Windows消息(前綴為WM_ )
????????分為三類:鼠標消息、鍵盤消息和窗口消息
?(2)控件消息
????????控件或其他子窗口向父窗口發送WM_ COMMAND消息
(3 )命令消息
????????菜單項、工具欄按鈕、加速鍵等用戶界面對象發送的WM_ COMMAND消息。
●焦點消息: WM_ SETFOCUS,WM_ KILLFOCUS
●定時器消息: WM_ TIMER
????????( 1 )標準Windows消息- -鼠標消息
????????????????-WM_ LBUTTONDOWN :單擊鼠標左鍵時產生的消息
? ? ? ? ? ? ? ? -WM_ LBUTTONUP :放開鼠標左鍵時產生的消息
????????????????-WM_ RBUTTONDOWN ;單擊鼠標右鍵時產生的消息
????????????????-WM_ RBUTTONUP :放開鼠標右鍵時產生的消息
????????????????-WM_ LBUTTONDBLCLK :雙擊鼠標左鍵時產生的消息
????????????????-WM_ RBUTTONDBLCLK :雙擊鼠標右鍵時產生的
????????????????-WM_ MOUSEMOVE :鼠標在窗C中移動時產生的
????????( 1 )標準Windows消息- -鍵盤消息
????????-WM_KEYDOWN :按下一一個非系統鍵時產生的消息,附加信息參數wParam為按下鍵的虛擬鍵碼,虛擬鍵碼用以標識按下或釋放的鍵, IParam記錄按鍵的重復次數、掃描碼等狀態信息;
????????- WM_KEYUP :彈起一個非系統鍵時產生的消息
????????- WM_CHAR :按下一個非系統鍵時產生的消息加信息參數wParam為按下鍵的ASCII碼,IPare的意思同上;
????????( 1 )標準Windows消息- -窗口消息
????????????????- WM_CREATE : CreateWindows函數產生的消息;
????????????????-WM_CLOSE :關閉窗口時產生的消息;
????????????????- WM_DESTROY :消除窗口時由DestroyWindows()發出的消息
????????????????- WM_QUIT :退出應用程序時由PostQuitMessage()發出的消息
????????????????- WM_ PAINT ; Windows系統需重繪時產生的消息。
???????????????- WM_ SIZE
????????????????- WM_MOVE
3.對象與句柄
????????●句柄是代表某些資源的一個4字節長的數值,用于標識應用程序中不同的對象和同類對象中不同的實例
????????●所有的句柄類型以H開頭。常見Windows對象的句柄:
4.關于API
????????●應用程序是如何通知操作系統執行某個功能的呢?
????????????????-應用程序要完成某個功能是以函數調用的形式實現;
????????????????-同樣,應用程序也是以函數調用的方式來通知操作系統執行相應的功能的。
????????●操作系統把它所能夠完成的功能以函數的形式提供給應用程序使用,應用程序對這些函數的調用就叫做系統調用。
????????●這些函數的集合就是Windows操作系統提供給應用程序編程的接口(Application Programming Interface),簡稱Windows API。如CreateWindow()函數。
????????●API是大量函數加上數字常量、宏、結構、類型以及其它相關項的集合。
????????●大多數API函數定義在Windows.h的文件中,也可以從Windows平臺軟件開發包( SDK )中得到。
????????●根據Windows API函數的功能,可以將其分為三類
????????????????(1)管理函數:實現窗口的創建、移動和修改功能
????????????????(2)圖形設備函數:實現與設備無關的圖形操作功能
????????????????(3)系統服務函數:實現與操作系統有關的多種功能
三、Win32程序結構
1、Win32程序結構-WinMain函數
Win32程序示例
????????例5-1創建一個如圖所示的Windows窗口。 本例的目的在于說明創建Windows應用程序的方法、過程及消息的使用。
注意:●LRESULT?選擇"右鍵/ Go To Definition"可查看定義
????????●對于CALLBACK,表示函數調用方式,_stdcall 與_ cdecl是兩種不同的函數調用約定,區別在函數參數入棧的順序,由調用函數還是被調用函數將參數彈出棧,以及產生函數修飾名的方法。
1. WinMain函數
功能:
????????(1)注冊窗口類,建立窗口及執行其他必要的初始化工作。
????????(2)進入消息循環,根據從消息隊列中接收的消息,調用相應的處理過程。
????????(3)當消息循環檢索到WM_ QUIT消息時,終止程序擬
?WinMain函數有三個基本的組成部分:函數說明、初始化和消息循環。
1) WinMain函數:函數說明
int WINAPI WinMain
( HINSTANCE hThisInst, ||應用程序當前實例句柄
HINSTANCE hPrevInst, ||應用程序其他實例句柄
LPSTR IpszCmdLine, ||指向程序命令行參數的指針
int nCmdShow ||應用程序開始執行時窗口顯示方式的整數值標識,如最大化顯示或最小化顯示或隱藏顯示
)
2)創建一個完整的窗口需要經過下面四個操作步驟:
?初始化--窗口類的定義
typedef struct tagWNDCLASS
{
UINT style; //窗口類的樣式,一般設置為0
WNDPROC *IpfnWndProc; //定義指向窗口函數的指針
int cbClsExtra; //窗口類變量占用的存儲空間
int cbWndExtra; //實例變量占用的存儲空間
HINSTANCE hInstance; //該類的應用程序的實例句柄
HICON hIcon; //圖標,調用Loadlcon
HCURSOR hCursor; //光標,調用L oadCursor
HBRUSH hbrBackground; //背景刷,調用GetStockObject
LPCTSTR lpszMenuName; //窗口類菜單資源名
LPCTSTR IpszClassName; //窗口類名
}WNDCLASS;
案例的窗口類定義代碼:
//窗口類的定義
WNDCL ASS wndclass ; //窗口類對象
wndclass .style=0; //窗口類型為缺省類型
wndclass. lpfnWndProc=WndProc; //定 義窗口處理函數名
wndclass.cbClsExtra=0; //窗口類無擴展
wndclass.cbWndExtra=0; //窗口實例無擴展
wndclass. hInstance=hInstance; //當前實例句柄
wndclass.hlcon=L oadlcon(NULL,IDI_APPLICATION); //窗口的最小化圖標為缺省圖標
wndclass. hCursor=L oadCursor(NULL,IDC_ARROW); //窗口采用箭頭光標
wndclass. hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //窗口背景為白色
wndclass.IpszMenuName=NULL; //窗口中無菜單
wndclass. IpszClassName=lpszClassName;//窗類名
Loadlcon:在應用程序中加載一個窗口圖標。 原型:HICON Loadlcon(HINSTANCE hInstance, LPCTSTR?IplconName )
? ? ? ? 其中第一個參數(HINSTANCE hInstance)表示圖標資源所在的模塊句柄,NULL則使用系統預定義圖標;第二個參數(LPCTSTR?IplconName)表示圖標資源名或系統預定義圖標標識名
?應用程序調用函數GetStockObject獲取系統提供的背景刷HBRUSH GetStockObject(int nBrush)
?窗口注冊代碼:
//窗口類的注冊
if(!RegisterClass( &wndclass)) //如果注冊失敗則發出警告
{ MessageBeep(0);
return FALSE;
}
窗口創建:
//創建窗口
HWND hwnd;//窗口句柄
hwnd = CreateWindow
(IpszClassName, //窗口類名
IpszTitle, //窗口實例的標題名,
WS_ OVERLAPPEDWINDOW, //窗口的風格
CW_ USEDEFAULT, //窗口左 上角坐標為缺省值
CW_ USEDEFAULT,
CW USEDEFAULT, //窗口的高和寬為缺省值
CW USEDEFAULT,
NULL, //此窗口無父窗口
NULL, //此窗口 無主菜單
hInstance, //創建此窗口的應用程序的當前句柄
NULL //不使用該值
),
創建一個窗口類的實例由函數CreateWindow()實現
HWND CreateWindow
(LPCTSTR IpszClassName, ||窗口類名
LPCTSTR IpszTitle, || 窗口標題名
DWORD dwStyle, || 創建窗口的樣式,如下頁表所示
int x,y, ||窗口左上角坐標
int nWidth,nHeight, ||窗口寬度和高度
HWND hwndParent, ||無父窗口則為NULL
HWENU hMenu, ||窗口主菜單句柄
HINSTANCE hInstance, || 創建窗的應用程序當前句柄
LPVOID IpParam ||創建窗口時指定的額外參數
)
常用窗口樣式
運用樣式方法:#define WS_OVERL APPEDWINDOW(WS OVERL APPED | WS_ CAPTION | WS_ SYSMENUIWS THICKFRAME | WS MINIMIZEBOX | WS MAXIMIZEBOX)
顯示窗口:
//顯示窗口
ShowWindow( hwnd, nCmdShow);
//立即發送WM_ PAINT消息來刷新窗口客戶區
UpdateWindow(hwnd);
消息循環:
//消息循環
MSG Msg;//消息
while( GetMessage(&Msg,NULL,0,0))
{ TranslateMessage( &Msg); //將虛擬鍵消息轉換為字符消息
DispatchMessage( &Msg); //調度一個消息給窗口程序。通常調度從GetMessage取得的消息
return Msg.wParam; //消息循環結束即程序終止時將信息返回
}
整合的窗口代碼:
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINS TANCE hInstance,HINSTANCE
hPrevInst,LPSTR IpszCmdLine,int nCmdShow)
{ WNDCL ASS wndclass ; //窗口類的定義... //為窗口類結構體中的成員賦值
RegisterClass( &wndclass));
CreateWindow(...);
ShowWindow( hwnd, nCmdShow);
UpdateWindow(hwnd);
//消息循環
MSG Msg;//消息
while( GetMessage(&Msg,NULL,0,0))
{ TranslateMessage( &Msg); //將虛擬鍵消息轉換為字符消息
DispatchMessage( &Msg); //調度一個消息給窗口程序。通常調度從GetMessage取得的消息
return Msg.wParam; //消息循環結束即程序終止時將信息返回
}
3) WinMain函數:消息循環
?函數GetMessage():返回零值,即檢索到WM_QUIT消息,程序結束循環并退出
GetMessage
( lpMSG, //指向MSG結構的指針 ,
//它包含有從應用程序消息隊列中檢索到的一條消息數據
hwnd, //指定為哪個窗口檢索消息,若為NULL,
//則檢索調用該函數的應用程序的所有消息
nMsgFilteMin, /指定檢索在Min和Max范圍內的消息
nMsgFilterMax
//若這兩個參數都為零,該函數檢索所有的可用的消息
)
函數TranslateMessage(&Msg):將原始鍵盤消息WM_KEYDOWN和WM_ KEYUP轉化為字符(WM_CHAR)消息
函數DispatchMessage(&Msg):將消息傳送到指定窗口函數
2.窗口函數WndProc
????????WndProc定義了應用程序對接收到的不同消息的響應;它包含了對各種可能接收到的消息的處理過程。????????
????????●WndProc函數由一個或多個switch語句組成。
????????●每一條case語句對應一種消息,當應用程序接收到一個消息時,相應的case語句被激活并執行相應的響應程序模塊。
LRESULT CALLBACK WndProc( HWND hwnd, UINT
messgae, WPARAM wParam,LPARAM IParam )
{.
..
switch(message) || message為標識的消息
{ case....break;
..case WM_ DESTROY:PostQuitMessage(0); break; default:return
DefWindowProc(hwnd,message,wParam,IParam); //為未定義處理過程的消息提供缺省處理
}
return(0);
}
????????在消息處理程序段中一般都有對WM_ DESTROY的處理,該消息是關閉窗口時發出的。它向應用程序發出WM_ QUIT消息,請求退出處理函數:
????????void PostQuitMessage(int nExitCode)????????//nExitCode為應用程序的退出代碼
案例窗口函數:
// 窗口(消息)處理函數
LRESULT CALL BACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM IParam)
{HDC hdc; // 設備描述表的句柄switch (message){case WM_PAINT:PAINTSTRUCT ps;hdc = BeginPaint(hWnd, &ps);TextOut(hdc, 0, 0, "武漢理工大學理學院", strlen("武漢理工大學理學院"));EndPaint(hWnd, &ps);break;case WM_CHAR:char szChar[20];sprintf(szChar, "char %C is %d", wParam, wParam); // 格式輸出內容到szCharMessageBox(hWnd, szChar, "顯示", 0);break;case WM_LBUTTONDOWN:MessageBox(hWnd, "mouse left clicked", "提示", 0);hdc = GetDC(hWnd);TextOut(hdc, 0, 50, "物理系電信科", strlen("物理系電信科"));ReleaseDC(hWnd, hdc);break;case WM RBUTTONDOWN:MessageBox(hWnd, "mouse right clicked", "提示", 0);hdc = GetDC(hWnd);TextOut(hdc,0, 100, "物理系光信科" ,strlen("物理系光信科");ReleaseDC(hWnd, hdc);case WM_CLOSE:if(IDYES==MessageBox(hWnd, "是否真的結束?", "關閉提示",MB_YESNOCANCEL))DestroyWindow(hWnd);break;case WM_DESTROY:PostQuitMessage(0); //調用PostQuitMessage發出WM_ QUIT消息break;default: //缺省時采用系統消息缺省處理函數return DefWindowProc(hWnd,message,wParam,lParam);}return (0);
}
Windows程序和消息的基本流程:
?