Windows應(yīng)用程序的基本結(jié)構(gòu).ppt
《Windows應(yīng)用程序的基本結(jié)構(gòu).ppt》由會(huì)員分享,可在線(xiàn)閱讀,更多相關(guān)《Windows應(yīng)用程序的基本結(jié)構(gòu).ppt(135頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
Windows應(yīng)用程序框架結(jié)構(gòu),哈爾濱工程大學(xué),概述,理解Window編程所使用的事件驅(qū)動(dòng)模型 Window編程的基本框架,Windows平臺(tái)下可視化開(kāi)發(fā)工具,可視化開(kāi)發(fā)系統(tǒng)集成了一系列系統(tǒng)可用資源和開(kāi)發(fā)工具 1、程序調(diào)試工具包括源程序語(yǔ)法檢查、可執(zhí)行程序修改和運(yùn)行監(jiān)視等 2、源程序編輯器和編譯器 3、資源管理器,包括圖形化窗口及組成元素的多種對(duì)象的編輯器 4、系統(tǒng)函數(shù)庫(kù)和系統(tǒng)函數(shù)開(kāi)發(fā)工具 5、可選擇并構(gòu)成具體語(yǔ)句或源程序結(jié)構(gòu)的例程庫(kù)及Help,Windows程序的特點(diǎn),大致說(shuō)來(lái)windows編程有兩種方法: a.windows c方式(SDK),SDK編程就是直接調(diào)用windows的API進(jìn)行編程; b.c++方式:即對(duì)SDK函數(shù)進(jìn)行包裝,如VC的MFC,BCB的OWL等。MFC把這些API封閉起來(lái),共有一百多個(gè)類(lèi)組成. API,全稱(chēng)application program interface,意思是應(yīng)用程序編程接口(說(shuō)起API并不僅僅指windows而言, windows支持的API叫winapi)。winapi就是應(yīng)用程序和windows之間通訊的一個(gè)編程界面。windows提供了上千個(gè)API函數(shù),以方便程序員來(lái)編寫(xiě)應(yīng)用程序。,Windows程序的特點(diǎn),WinSDK程序設(shè)計(jì)就是API方式的windows程序設(shè)計(jì)。SDK,全稱(chēng)Software Developers Kit,意思是軟件開(kāi)發(fā)工具箱。 MFC,全稱(chēng)Microsoft Foundation Classes,偽軟把WinAPI進(jìn)行封裝的類(lèi)庫(kù)。它是一個(gè)類(lèi)的集合,通過(guò)覆蓋WinAPI,為編程提供了一個(gè)面向?qū)ο蟮慕缑?。它使windows程序員能夠利用C++面象對(duì)象的特性進(jìn)行編程,類(lèi)似BCB的OWL,Delphi的VCL組件。它把那些進(jìn)行SDK編程時(shí)最繁瑣的部分提供給程序員,使之專(zhuān)注于功能的實(shí)現(xiàn)。你不妨把它想象成類(lèi)似TC提供的函數(shù)庫(kù)吧。,SDK編程,利用Windows API函數(shù)編寫(xiě)Windows應(yīng)用程序必須首先了解以下內(nèi)容: (1)窗口的概念 (2)事件驅(qū)動(dòng)的概念 (3)句柄 (4)消息,Windows的事件驅(qū)動(dòng)機(jī)制,Dos的過(guò)程驅(qū)動(dòng)與Windows的事件驅(qū)動(dòng) 在講Window消息循環(huán)之前,我想先談一下Dos與Windows驅(qū)動(dòng)機(jī)制的區(qū)別: DOS程序主要使用順序的,過(guò)程驅(qū)動(dòng)的程序設(shè)計(jì)方法。順序的,過(guò)程驅(qū)動(dòng)的程序有一個(gè)明顯的開(kāi)始,明顯的過(guò)程及一個(gè)明顯的結(jié)束,因此程序能直接控制程序事件或過(guò)程的順序。 而Windows的驅(qū)動(dòng)方式是事件驅(qū)動(dòng),就是不由事件的順序來(lái)控制,而是由事件的發(fā)生來(lái)控制,所有的事件是無(wú)序的,作為一個(gè)windows程序員,在你編寫(xiě)程序時(shí),你并不知道用戶(hù)先按哪個(gè)按紐,也不知道程序先觸發(fā)哪個(gè)消息。你的任務(wù)就是對(duì)正在開(kāi)發(fā)的應(yīng)用程序要發(fā)出或要接收的消息進(jìn)行排序和管理。,過(guò)程驅(qū)動(dòng)方法和事件驅(qū)動(dòng)方法,Dos編程和Windows編程不同,dos下的C編程的main()一樣,windows下的入口是WinMain()函數(shù)。 WinMain()所起的作用:初始化,展示窗口,銷(xiāo)毀應(yīng)用程序等。 第一個(gè)參數(shù):應(yīng)用程序的當(dāng)前實(shí)例句柄。 第二個(gè)參數(shù):應(yīng)用程序的前一個(gè)實(shí)例句柄,別管它,對(duì)于Win32位而言,它一般是NULL. 第三個(gè)參數(shù):指向任何傳給程序的命令行參數(shù)。PSTR代表“指向字符串的指針“。 第四個(gè)參數(shù):它告訴應(yīng)用程序如何初始化窗口,如最大化,最小化等狀態(tài)。,WinMain函數(shù)的功能,三個(gè)基本的組成部分:函數(shù)說(shuō)明、初始化和消息循環(huán),,WinMain函數(shù),,注意!Win是多任務(wù)管理的,同一應(yīng)用程序的多個(gè)窗口可能會(huì)同時(shí)存,Win系統(tǒng)對(duì)每個(gè)窗口的執(zhí)行稱(chēng)為一個(gè)實(shí)例,并用一個(gè)實(shí)例句柄來(lái)唯一標(biāo)識(shí),Windows常見(jiàn)的數(shù)據(jù)類(lèi)型,在Windows.h中定義了Windows 應(yīng)用程序中包含種類(lèi)繁多的數(shù)據(jù)類(lèi)型,重要的數(shù)據(jù)結(jié)構(gòu),兩者句柄定義的不同,句柄(handle): 在標(biāo)準(zhǔn)C庫(kù)中句柄用來(lái)對(duì)文件輸入輸出。 在Windows環(huán)境中,句柄是用來(lái)標(biāo)識(shí)項(xiàng)目的,這些項(xiàng)目包括: *.模塊(module) *.任務(wù)(task) *.實(shí)例(instance) *.文件(file) *.內(nèi)存塊(block of memory) *.菜單(menu) *.控制(control) *.字體(font) *.資源(resource),包括圖標(biāo)(icon),光標(biāo)(cursor),字符串(string) *.GDI對(duì)象(GDI object),包括位圖(bitmap),畫(huà)刷(brush),元文件(metafile),調(diào)色板(palette),畫(huà)筆(pen),區(qū)域(region),以及設(shè)備描述表(device context)。 WINDOWS程序中并不是用物理地址來(lái)標(biāo)識(shí)一個(gè)內(nèi)存塊,文件,任務(wù)或動(dòng)態(tài)裝入模塊的,相反的,WINDOWS API給這些項(xiàng)目分配確定的句柄,并將句柄返回給應(yīng)用程序,然后通過(guò)句柄來(lái)進(jìn)行操作。,句柄是什么?,在Win32里,句柄是指向一個(gè)無(wú)值型對(duì)象(void *)的指針,是一個(gè)4字節(jié)長(zhǎng)的數(shù)據(jù)”。句柄并不是一個(gè)真正意義上的指針。從結(jié)構(gòu)上看,句柄的確是一個(gè)指針,盡管它沒(méi)有指向用于存儲(chǔ)某個(gè)對(duì)象的內(nèi)存位置,而實(shí)際上句柄指向的是一個(gè)包含了對(duì)該對(duì)象進(jìn)行的引用的位置。我們天氣熱搖扇子的時(shí)候只要抓住扇柄便可以控制整個(gè)扇子的運(yùn)動(dòng)了,在程序中也差不多是這個(gè)意思。通常一個(gè)句柄就可以傳遞我們所要做的事情。有經(jīng)驗(yàn)的開(kāi)發(fā)者肯定清楚,編寫(xiě)程序總是要和各種句柄打交道的,句柄是系統(tǒng)用來(lái)標(biāo)識(shí)不同對(duì)象類(lèi)型的工具,如窗口、菜單等,這些東西在系統(tǒng)中被視為不同類(lèi)型的對(duì)象,用不同的句柄將他們區(qū)分開(kāi)來(lái)。,句柄,常用句柄類(lèi)型及其說(shuō)明,,應(yīng)用程序通過(guò) 句柄訪(fǎng)問(wèn)相應(yīng) 的對(duì)象信息,HWND 窗口句柄 HDC 設(shè)備環(huán)境句柄 HBITMAP 位圖句柄 HCURSOR 光標(biāo)句柄 HICON 圖標(biāo)句柄 HFONT 字體句柄 HMENU 菜單句柄 HPEN 畫(huà)筆句柄 HFILE 文件句柄 HBRUSH 畫(huà)刷句柄 HINSTANCE 當(dāng)前實(shí)例句柄,Windows程序的特點(diǎn),窗口句柄: 系統(tǒng)通過(guò)窗口句柄來(lái)在整個(gè)系統(tǒng)中唯一標(biāo)識(shí)一個(gè)窗口,發(fā)送一個(gè)消息時(shí)必須指定一個(gè)窗口句柄表明該消息由那個(gè)窗口接收。而每個(gè)窗口都會(huì)有自己的窗口過(guò)程,所以用戶(hù)的輸入就會(huì)被正確的處理。 所有的命名采用了匈牙利表示法。如消息的前綴使用msg.句柄使用h.函數(shù)使用fn等。 Windows程序則至少兩個(gè)主程序, 一個(gè)是WinMain(), int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state );,Windows程序的特點(diǎn),另一個(gè)是窗口過(guò)程函數(shù)WndProc,它的函數(shù)原型為: long FAR PASCAL WndProc(HWND hWnd,WORD message,WORD wParam,LONG lParam); 窗口函數(shù)與回調(diào)函數(shù): 在Windows中,應(yīng)用程序通過(guò)要求Windows完成指定操作,而承擔(dān)這項(xiàng)通信任務(wù)的API函數(shù)就是Windows的相應(yīng)窗口函數(shù)WndProc。應(yīng)用程序不直接調(diào)用任何窗口函數(shù),而是等待Windows調(diào)用窗口函數(shù),請(qǐng)求完成任務(wù)或返回信息。為保證Windows調(diào)用這個(gè)窗口函數(shù),這個(gè)函數(shù)必須先向Windows登記,然后在Windows實(shí)施相應(yīng)操作時(shí)回調(diào),所以窗口函數(shù)又稱(chēng)為回調(diào)函數(shù)。WndProc是一個(gè)主回調(diào)函數(shù),Windows至少有一個(gè)回調(diào)函數(shù)。典型的回調(diào)函數(shù)有窗口過(guò)程、對(duì)話(huà)框過(guò)程和鉤子函數(shù)。實(shí)際上,也許有不止一個(gè)的窗口過(guò)程。例如,每一個(gè)不同的窗口類(lèi)都有一個(gè)與之相對(duì)應(yīng)的窗口過(guò)程。 實(shí)例:在Windows中,能多次同時(shí)運(yùn)行同一個(gè)應(yīng)用程序,即運(yùn)行多個(gè)副本,每個(gè)副本叫做一個(gè)“實(shí)例”。,Windows程序的特點(diǎn),WinMain()函數(shù)的調(diào)用約定是PASCAL。 在這里PASCAL是一個(gè)調(diào)用約定,由于這種方式最早由PASCAL采用,所以這么叫。 在MSDN中的C++ Language Reference中,Calling Conventions這一章都是講調(diào)用約定的。 約定:微軟重定義了許多約定類(lèi)型,為的是可以讓代碼更容易跨平臺(tái)或者跨編譯器。 其實(shí),調(diào)用約定要解決兩個(gè)問(wèn)題,都是針對(duì)堆棧操作: 1。參數(shù)傳遞的順序(本質(zhì)是壓棧的順序) 2。誰(shuí)負(fù)責(zé)平棧(調(diào)用者還是調(diào)用對(duì)象) 一個(gè)函數(shù)的聲明、定義和實(shí)現(xiàn)中的調(diào)用方式一般都一致。 WINAPI標(biāo)識(shí)符的定義是:#define WINAPI __stdcall, __stdcall指Window調(diào)用函數(shù)的一種方式,也就是如何在堆中存取函數(shù)參數(shù)的方式。許多Windows Api函數(shù)調(diào)用聲明為_(kāi)_stdcall方式。,調(diào)用方式,1、_stdcall是Pascal程序的缺省調(diào)用方式,通常用于Win32 Api中,函數(shù)采用從右到左的壓棧方式,自己在退出時(shí)清空堆棧。VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線(xiàn)前綴,在函數(shù)名后加上“@”和參數(shù)的字節(jié)數(shù)(堆棧要求分配的字節(jié)數(shù) )。 如:_TestMethod@4 2、C調(diào)用約定(即用__cdecl關(guān)鍵字說(shuō)明)按從右至左的順序壓參數(shù)入棧,由調(diào)用者把參數(shù)彈出棧。另外,在函數(shù)名修飾約定方面也有所不同。 _cdecl是C和C++程序的缺省調(diào)用方式。每一個(gè)調(diào)用它的函數(shù)都包含清空堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比調(diào)用_stdcall函數(shù)的大。函數(shù)采用從右到左的壓棧方式。VC將函數(shù)編譯后會(huì)在函數(shù)名前面加上下劃線(xiàn)前綴。是MFC缺省調(diào)用約定。如 :_TestMethod,調(diào)用方式,CALLBACK和WINAPI函數(shù)是由你設(shè)計(jì)的函數(shù),但你不能“顯式”的調(diào)用它,而是Windows 系統(tǒng)自己調(diào)用,例如窗口過(guò)程函數(shù),枚舉函數(shù)等,這是由Windows系統(tǒng)的工作機(jī)制決定的。 至于這些函數(shù)為什么要是CALLBACK,且看下面詳解: CALLBACK,WINAPI等在windef.h中被如下定義: #define CALLBACK __stdcall #define WINAPI __stdcall #define WINAPIV __cdecl #define APIENTRY WINAPI #define APIPRIVATE __stdcall #define PASCAL __stdcall,調(diào)用方式舉例,CALLBACK就是要VC編譯器在編譯時(shí)采取非默認(rèn)(__cdecl)的方式(__stdcall),__stdcall和__cdecl最大的不同就是我前面說(shuō)的“堆棧指針恢復(fù)的責(zé)任歸屬”----C編譯器默認(rèn)(__cdecl)是主函數(shù)來(lái)恢復(fù)stack指針SP,若指定關(guān)鍵字__stdcall,則編譯器生成的碼是由被調(diào)函數(shù)自己恢復(fù)SP,看看下面的例子:假如有一個(gè)函數(shù)聲明如 int __stdcall getMax(int a ,int b); 返回兩者中較大值。在主函數(shù)中被調(diào)用,調(diào)用時(shí)VC造出的碼如下:(其它編譯器可能不同) 0040102B push 38h ;參數(shù)b 0040102D push 60h ;a 0040102F call @ILT+15(_getMax)(0x0040100f) ; call getMax() . . 為 getMax()造出的匯編語(yǔ)句是 00401020 push ebp 00401021 mov ebp,esp . . . .;其它指令 00401026 pop ebp 00401027 ret 8 ;在返回時(shí)修改堆棧指針,調(diào)用方式舉例,若聲明及定義時(shí)無(wú) __stdcal,VC造出的碼如下: 0040102B push 38h 0040102D push 60h 0040102F call @ILT+15(_getMax)(0x0040100f) 00401034 add esp,8 ;esp由主函數(shù)恢復(fù) . . 為 getMax()造出的匯編語(yǔ)句是 00401020 push ebp 00401021 mov ebp,esp . . . .;其它指令 00401026 pop ebp 00401027 ret ;返回 現(xiàn)在你該知CALLBACK 與不加CALLBACK 的函數(shù)在調(diào)用以及返回上有什么區(qū)別了吧。,Windows程序的特點(diǎn),用位的“或”操作(操作符“|”)把若干個(gè)常數(shù)組合起來(lái)控制消息窗口顯示的按鈕和圖標(biāo)等。在Windows.h中,以CS_開(kāi)頭的類(lèi)樣式(Class Style)標(biāo)識(shí)符被定義為16位的常量,這些常量都只有某1位為1。在VC++開(kāi)發(fā)環(huán)境中,可以看到CS_VREDRAW=0x0001,CS_HREDRAW=0x0002,CS_DBLCLKS =0x0008,CS_NOCLOSE=0x0200,將這些16進(jìn)制數(shù)轉(zhuǎn)換為2進(jìn)制數(shù),就可以發(fā)現(xiàn)它們都只有1位為1,并且為1的位各不相同。用這種方式定義的標(biāo)識(shí)符稱(chēng)為“位標(biāo)志”,我們可以使用位運(yùn)算操作符來(lái)組合使用這些樣式。例如,要讓窗口在水平和垂直尺寸發(fā)生變化時(shí)發(fā)生重繪,我們可以使用位或(|)操作符將CS_HREDRAW和CS_VREDRAW組合起來(lái),如style=CS_HREDRAW | CS_VREDRAW。假如有一個(gè)變量具有多個(gè)樣式,而我們并不清楚該變量都有哪些樣式,現(xiàn)在我們想要去掉該變量具有的某個(gè)樣式,那么可以先對(duì)該樣式標(biāo)識(shí)符進(jìn)行取反(~)操作,然后再和這個(gè)變量進(jìn)行與(&)操作即可實(shí)現(xiàn)。例如,要去掉先前的style變量所具有的CS_VREDRAW樣式,可以編寫(xiě)代碼:style=style & ~ CS_VREDRAW。 在Windows程序中,經(jīng)常會(huì)用到這種位標(biāo)志標(biāo)識(shí)符,后面我們?cè)趧?chuàng)建窗口時(shí)用到的窗口樣式,也是屬于位標(biāo)志標(biāo)識(shí)符。,Windows程序的特點(diǎn),在Windows應(yīng)用程序中,每一個(gè)窗口都必須從屬于一個(gè)窗口類(lèi),窗口類(lèi)定義了窗口所具有的屬性,如它的樣式、圖標(biāo)、鼠標(biāo)指針、菜單名稱(chēng)及窗口過(guò)程名等。 窗口種類(lèi)是定義窗口屬性的模板,這些屬性包括窗口式樣,鼠標(biāo)形狀,菜單等等,窗口種類(lèi)也指定處理該類(lèi)中所有窗口消息的窗口函數(shù).只有先建立窗口種類(lèi),才能根據(jù)窗口種類(lèi)來(lái)創(chuàng)建Windows應(yīng)用程序的一個(gè)或多個(gè)窗口.創(chuàng)建窗口時(shí),還可以指定窗口獨(dú)有的附加特性.窗口種類(lèi)簡(jiǎn)稱(chēng)窗口類(lèi),窗口類(lèi)不能重名.在建立窗口類(lèi)后,必須向Windows登記.建立窗口類(lèi)就是用WNDCLASS結(jié)構(gòu)定義一個(gè)結(jié)構(gòu)變量。,窗口的創(chuàng)建過(guò)程,窗口的創(chuàng)建過(guò)程需要四個(gè)步驟,下面列出了創(chuàng)建步驟和這個(gè)過(guò)程中涉及的類(lèi)和函數(shù): 1.設(shè)計(jì)一個(gè)窗口類(lèi)//很多特征(光標(biāo),圖標(biāo),背景)WNDCLASS 2.注冊(cè)窗口類(lèi)//RegisterClass 3.創(chuàng)建窗口//首先定義句柄 如:HWND hwnd; CreateWindow 4.顯示及更新窗口//顯示窗口:ShowWindow,更新窗口:UpdateWindow,理解Window編程所使用的事件驅(qū)動(dòng)模型,事件,消息,消息隊(duì)列和消息循環(huán) Windows應(yīng)用程序是遵循事件驅(qū)動(dòng)模型,通常Windows程序啟動(dòng)后只是等待某些事件的發(fā)生(當(dāng)然應(yīng)用程序也可以進(jìn)行空閑處理-當(dāng)沒(méi)有事件發(fā)生時(shí)(WM_IDLE)執(zhí)行某些特定的任務(wù))。事件有多種產(chǎn)生途徑,包括: 鍵盤(pán)中某些鍵按下,鼠標(biāo)單擊,當(dāng)窗口創(chuàng)建時(shí),尺度發(fā)生變化時(shí)(Windows系統(tǒng)發(fā)給你的),發(fā)生移動(dòng),被關(guān)閉,最小化,最大化或變?yōu)榭梢?jiàn)狀態(tài)時(shí)等。 當(dāng)某一個(gè)事件發(fā)生時(shí),Windows會(huì)為該事件所針對(duì)的應(yīng)用程序發(fā)送一條消息,表明該事件發(fā)生了,并在該應(yīng)用程序的消息隊(duì)列中增加一條消息,該消息隊(duì)列只是保存了應(yīng)用程序所接受的消息的一個(gè)優(yōu)先隊(duì)列(會(huì)根據(jù)消息的優(yōu)先級(jí)排列)。應(yīng)用程序要做的事,就是在一個(gè)消息循環(huán)中不斷地檢查消息隊(duì)列,當(dāng)接收到一條消息時(shí),便將其分派給接收該消息的特定窗口的窗口過(guò)程。一個(gè)應(yīng)用程序可能含有很多的窗口,窗口過(guò)程是一個(gè)與應(yīng)用程序各窗口相關(guān)的特殊函數(shù)。(每一個(gè)窗口都有一個(gè)窗口過(guò)程,但多個(gè)窗口可以共用一個(gè)窗口過(guò)程),他就是我們實(shí)現(xiàn)的用于處理消息的函數(shù)。,事件驅(qū)動(dòng)編程模型,事件,,Window操作系統(tǒng)檢測(cè)到 某一個(gè)事件的發(fā)生。作為 響應(yīng),Windows將給特定程 序的消息隊(duì)列發(fā)送一條消息,,,,,應(yīng)用程 序A消 息隊(duì)列,應(yīng)用程 序B消 息隊(duì)列,應(yīng)用程 序C消 息隊(duì)列,當(dāng)一條消息到來(lái)時(shí),消息隊(duì) 列會(huì)一直將該消息保存到應(yīng)用程序準(zhǔn)備 對(duì)其進(jìn)行處理為止。所以,如果應(yīng)用層 序正處在忙碌狀態(tài),該消息便不會(huì)立即被 處理。此外,優(yōu)先級(jí)較高的消息會(huì)在優(yōu)先級(jí) 較低的消息之前優(yōu)先得到處理。,,,應(yīng)用程序A的 消息循環(huán),應(yīng)用程序B的 消息循環(huán),應(yīng)用程序C的 消息循環(huán),,,窗口過(guò)程C,,窗口過(guò)程C,,窗口過(guò)程C,,應(yīng)用程序的消息循環(huán)不斷地檢查消 息是否到來(lái),當(dāng)“獲取”一條 消息時(shí),該消息便被發(fā)送給窗口過(guò) 程WndProc,該函數(shù)為消息的傳遞的目 的地。,,窗口過(guò)程是一個(gè)由應(yīng)用程序開(kāi) 發(fā)人員定義的函數(shù)。該函數(shù)由windows 系統(tǒng)自動(dòng)調(diào)用。注意,一個(gè)單個(gè)應(yīng) 用程序允許有多窗口函數(shù),,,Case WM_CREATE: Case WM_KEYDOWN: Case WM_DESTROY: 在窗口處理函數(shù)內(nèi)部,編 寫(xiě)消息處理操作,消息?,消息系統(tǒng)對(duì)于一個(gè)win32程序來(lái)說(shuō)十分重要,它是一個(gè)程序運(yùn)行的動(dòng)力源泉。一個(gè)消息,是系統(tǒng)定義的一個(gè)32位的值,他唯一的定義了一個(gè)事件,向Windows發(fā)出一個(gè)通知,告訴應(yīng)用程序某個(gè)事情發(fā)生了。例如,單擊鼠標(biāo)、改變窗口尺寸、按下鍵盤(pán)上的一個(gè)鍵都會(huì)使Windows發(fā)送一個(gè)消息給應(yīng)用程序。 消息本身是作為一個(gè)記錄傳遞給應(yīng)用程序的,這個(gè)記錄中包含了消息的類(lèi)型以及其他信息。例如,對(duì)于單擊鼠標(biāo)所產(chǎn)生的消息來(lái)說(shuō),這個(gè)記錄中包含了單擊鼠標(biāo)時(shí)的坐標(biāo)。這個(gè)記錄類(lèi)型叫做MSG,MSG含有來(lái)自windows應(yīng)用程序消息隊(duì)列的消息信息。 消息可以由系統(tǒng)或者應(yīng)用程序產(chǎn)生。系統(tǒng)在發(fā)生輸入事件時(shí)產(chǎn)生消息。舉個(gè)例子, 當(dāng)用戶(hù)敲鍵, 移動(dòng)鼠標(biāo)或者單擊控件。系統(tǒng)也產(chǎn)生消息以響應(yīng)由應(yīng)用程序帶來(lái)的變化, 比如應(yīng)用程序改變系統(tǒng)字體改變窗體大小。應(yīng)用程序可以產(chǎn)生消息使窗體執(zhí)行任務(wù),或者與其他應(yīng)用程序中的窗口通訊。,消息中有什么?,它在Windows中聲明如下: typedef struct tagMsg { HWND hwnd; 接受該消息的窗口句柄 UINT message; 消息常量標(biāo)識(shí)符,也就是我們通常所說(shuō)的消息號(hào) WPARAM wParam; 32位消息的特定附加信息,確切含義依賴(lài)于消息值 LPARAM lParam; 32位消息的特定附加信息,確切含義依賴(lài)于消息值 DWORD time; 消息創(chuàng)建時(shí)的時(shí)間 POINT pt; 消息創(chuàng)建時(shí)的鼠標(biāo)/光標(biāo)在屏幕坐標(biāo)系中的位置 }MSG;,Msg消息結(jié)構(gòu)內(nèi)容,Windows系統(tǒng)的消息機(jī)制都包含2個(gè)長(zhǎng)整型的參數(shù):WPARAM, LPARAM,可以存放指針,也就是說(shuō)可以指向任何內(nèi)容了。 傳遞的內(nèi)容因消息各異,消息處理函數(shù)會(huì)根據(jù)消息的類(lèi)型進(jìn)行特別的處理,它知道傳遞的參數(shù)是什么含義。 消息在線(xiàn)程內(nèi)傳遞時(shí),由于在同一個(gè)地址空間中,指針的值是有效的。但是夸線(xiàn)程的情況就不能直接使用指針了,所以Windows系統(tǒng)提供了 WM_SETTEXT, WM_GETTEXT, WM_COPYDATA等消息,用來(lái)特殊處理,指針的內(nèi)容會(huì)被放到一個(gè)臨時(shí)的內(nèi)存映射文件(Memory-mapped File)里面,通過(guò)它實(shí)現(xiàn)線(xiàn)程間的共享數(shù)據(jù)。,消息隊(duì)列和線(xiàn)程的關(guān)系是什么?,消息隊(duì)列的創(chuàng)建:當(dāng)一個(gè)線(xiàn)程第一次被創(chuàng)建時(shí),系統(tǒng)假定線(xiàn)程不會(huì)用于任何與用戶(hù)相關(guān)的任務(wù)。這樣可以減少線(xiàn)程對(duì)系統(tǒng)資源的要求。但是,一旦該線(xiàn)程調(diào)用一個(gè)與圖形用戶(hù)界面有關(guān)的函數(shù) ( 如檢查它的消息隊(duì)列或建立一個(gè)窗口 ),系統(tǒng)就會(huì)為該線(xiàn)程分配一個(gè)消息隊(duì)列 ,以便它能夠執(zhí)行與用戶(hù)界面有關(guān)的任務(wù)。 操作系統(tǒng)可能為任何線(xiàn)程創(chuàng)建消息隊(duì)列,只要該線(xiàn)程調(diào)用了消息獲取函數(shù),甚至都不需要該線(xiàn)程創(chuàng)建任何窗口。 如果句柄是NULL,DispatchMessage不做任何事。因此在處理線(xiàn)程消息的時(shí)候不能用DispatchMessage處理,而是直接處理,線(xiàn)程一般沒(méi)有窗口。如下: DispatchMessage函數(shù)需要輸入一個(gè)指向MSG結(jié)構(gòu)的指針(當(dāng)然這個(gè)MSG結(jié)構(gòu)可以是以前GetMessage或者PeekMessage獲得的)。DispatchMessage會(huì)傳送窗口句柄,消息標(biāo)識(shí)符,兩個(gè)消息參數(shù)給窗口過(guò)程函數(shù),但是他不會(huì)傳送時(shí)間和鼠標(biāo)位置信息。應(yīng)用程序在處理消息的時(shí)候可以通過(guò)調(diào)用GetMessageTime和GetMessagePos函數(shù)獲得這兩個(gè)信息。,消息隊(duì)列的資源體,線(xiàn)程處理消息的例程,如果參數(shù)lpmsg指向一個(gè)WM_TIMER消息,并且WM_TIMER消息的參數(shù)IParam不為NULL,則調(diào)用IParam指向的函數(shù),而不是調(diào)用窗口程序。 見(jiàn)線(xiàn)程\multi1thread1中的 CreateMsgThread和GetMesgThread 函數(shù)中調(diào)用PeekMessage的用意。,沒(méi)有窗口如何發(fā)消息?,向一個(gè)線(xiàn)程傳遞消息可以使用PostThreadMessage,這個(gè)函數(shù)的接口很明確,要求傳遞一個(gè)線(xiàn)程Id,但是還有PostMessage和SendMessage這樣的API,要求傳遞的是窗口句柄,這可能就是我們此前會(huì)迷惑于消息隊(duì)列是跟窗口相關(guān)還是跟線(xiàn)程相關(guān)的原因。事實(shí)上,在調(diào)用PostMessage或SendMessage的時(shí)候,系統(tǒng)要根據(jù)傳入的窗口句柄,確認(rèn)是哪一個(gè)線(xiàn)程創(chuàng)建了該窗口(我們也可以通過(guò)GetWindowsThreadProcessId自行獲取是哪個(gè)線(xiàn)程創(chuàng)建了一個(gè)窗口),然后系統(tǒng)分配一塊內(nèi)存,將消息參數(shù)存儲(chǔ)在這塊內(nèi)存中,并將這塊內(nèi)存增加到相應(yīng)線(xiàn)程的登記消息隊(duì)列中。 線(xiàn)程中可以有消息循環(huán),消息循環(huán)將線(xiàn)程中的消息取出來(lái)并且進(jìn)行處理——可以自行根據(jù)消息的類(lèi)型進(jìn)行處理,也可以交給DispatchMessage處理,該API會(huì)回調(diào)窗口類(lèi)中的窗口處理函數(shù)(依據(jù)該窗口所屬窗口類(lèi)別WNDCLASS的不同分別回調(diào)不同的消息處理函數(shù))。如果線(xiàn)程創(chuàng)建了窗口,那么窗口的各種響應(yīng)事件全部是由消息循環(huán)以及相關(guān)處理完成的,一個(gè)消息循環(huán)可以處理很多個(gè)窗口的消息。,消息分類(lèi),隊(duì)列消息和非隊(duì)列消息:從消息的發(fā)送途徑上看,消息分兩種:隊(duì)列消息和非隊(duì)列消息。 隊(duì)列消息送到系統(tǒng)消息隊(duì)列,然后到線(xiàn)程消息隊(duì)列;非隊(duì)列消息直接送給目的窗口過(guò)程。這里,對(duì)消息隊(duì)列闡述如下: Windows維護(hù)一個(gè)系統(tǒng)消息隊(duì)列,每個(gè)GUI線(xiàn)程有一個(gè)線(xiàn)程消息隊(duì)列(Thread message queue)。鼠標(biāo)、鍵盤(pán)事件由鼠標(biāo)或鍵盤(pán)驅(qū)動(dòng)程序轉(zhuǎn)換成輸入消息并把消息放進(jìn)系統(tǒng)消息隊(duì)列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。Windows每次從系統(tǒng)消息隊(duì)列移走一個(gè)消息,確定它是送給哪個(gè)窗口的和這個(gè)窗口是由哪個(gè)線(xiàn)程創(chuàng)建的,然后,把它放進(jìn)窗口創(chuàng)建線(xiàn)程的線(xiàn)程消息隊(duì)列。線(xiàn)程消息隊(duì)列接收送給該線(xiàn)程所創(chuàng)建窗口的消息。線(xiàn)程從消息隊(duì)列取出消息,通過(guò)Windows把它送給適當(dāng)?shù)拇翱谶^(guò)程來(lái)處理。除了鍵盤(pán)、鼠標(biāo)消息以外,隊(duì)列消息還有WM_PAINT、WM_TIMER和WM_QUIT。這些隊(duì)列消息以外的絕大多數(shù)消息是非隊(duì)列消息。,消息分類(lèi)?,windows中的消息雖然很多,但是種類(lèi)并不繁雜,大體上有3種:窗口消息、命令消息和控件通知消息。 窗口消息大概是系統(tǒng)中最為常見(jiàn)的消息,它是指由操作系統(tǒng)和控制其他窗口的窗口所使用的消息。例如CreateWindow、MoveWindow等都會(huì)激發(fā)窗口消息,還有我們?cè)谏厦嬲劦降膯螕羰髽?biāo)所產(chǎn)生的消息也是一種窗口消息。 命令消息,這是一種特殊的窗口消息,他用來(lái)處理從一個(gè)窗口發(fā)送到另一個(gè)窗口的用戶(hù)請(qǐng)求,例如按下一個(gè)按鈕,他就會(huì)向主窗口發(fā)送一個(gè)命令消息。 控件通知消息,是指這樣一種消息,一個(gè)窗口內(nèi)的子控件發(fā)生了一些事情,需要通知父窗口。通知消息只適用于標(biāo)準(zhǔn)的窗口控件如按鈕、列表框、組合框、編輯框,以及Windows公共控件如樹(shù)狀視圖、列表視圖等。例如,單擊或雙擊一個(gè)控件、在控件中選擇部分文本、操作控件的滾動(dòng)條都會(huì)產(chǎn)生通知消息。 她類(lèi)似于命令消息,當(dāng)用戶(hù)與控件窗口交互時(shí),那么控件通知消息就會(huì)從控件窗口發(fā)送到它的主窗口。但是這種消息的存在并不是為了處理用戶(hù)命令,而是為了讓主窗口能夠改變控件,例如加載、顯示數(shù)據(jù)。,常見(jiàn)的window消息,VC中存在幾種系統(tǒng)定義的消息分類(lèi),不同的前綴符號(hào)經(jīng)常用于消息宏識(shí)別消息附屬的分類(lèi),系統(tǒng)定義的消息宏前綴如下:,BM 表示按鈕控制消息 CB 表示組合框控制消息 DM 表示默認(rèn)下壓式按鈕控制消息 EM 表示編輯控制消息 LB 表示列表框控制消息 SBM 表示滾動(dòng)條控制消息 WM 表示窗口消息,Windows應(yīng)用程序常用消息,WM_LBUTTONDOWN:產(chǎn)生單擊鼠標(biāo)左鍵的消息,Windows應(yīng)用程序常用消息,此外,相似的消息還有: WM_LBUTTONUP:放開(kāi)鼠標(biāo)左鍵時(shí)產(chǎn)生; WM_RBUTTONDOWN:?jiǎn)螕羰髽?biāo)右鍵時(shí)產(chǎn)生; WM_RBUTTONUP:放開(kāi)鼠標(biāo)右鍵時(shí)產(chǎn)生; WM_LBUTTONDBLCLK:雙擊鼠標(biāo)左鍵時(shí)產(chǎn)生; WM_RBUTTONDBLCLK:雙擊鼠標(biāo)右鍵時(shí)產(chǎn)生。,2.WM_KEYDOWN:按下一個(gè)非系統(tǒng)鍵時(shí)產(chǎn)生的消息,系統(tǒng)鍵是指實(shí)現(xiàn)系統(tǒng)操作的組合鍵,例如Alt與某個(gè)功能鍵的組合以實(shí)現(xiàn)系統(tǒng)菜單操作等,wParam:按下鍵的虛擬鍵碼,用以標(biāo)識(shí)按下或釋放的鍵 1Param:記錄了按鍵的重復(fù)次數(shù)、掃描碼、轉(zhuǎn)移代碼、先前鍵的狀態(tài)等信息。,如F1的虛擬鍵碼在Windows.h文 件中定義為VK_F1,相似的消息還有WM_KEYUP, 在放開(kāi)非系統(tǒng)鍵時(shí)產(chǎn)生,Windows應(yīng)用程序常用消息,3.WM_ CHAR:按下一個(gè)非系統(tǒng)鍵時(shí)產(chǎn)生的消息 wParam 為按鍵的ASCII碼 1Param 與WM_KEYDOWN的相同 4. WM_CREATE:由CreateWindow函數(shù)發(fā)出的消息 wParam:未用 1Param:包含一個(gè)指向CREATESTRUCT數(shù)據(jù)結(jié)構(gòu)的指針 5.WM_CLOSE:關(guān)閉窗口時(shí)產(chǎn)生的消息 wParam和1Param均未用。 6.WM_DESTROY:由DestroyWiodow函數(shù)發(fā)出的消息,Windows應(yīng)用程序常用消息,7. WM_QUIT:由PostQuitMessage函數(shù)發(fā)出的消息 退出應(yīng)用程序時(shí)發(fā)出的消息 wParam:含退出代碼,標(biāo)識(shí)程序退出運(yùn)行時(shí)的有關(guān)信息 1Param:未用 8. WM_PAINT,消息的接收,消息的接收主要有2個(gè)函數(shù):GetMessage、PeekMessage。 GetMessage原型如下:BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); GetMessage該函數(shù)用來(lái)獲取與hWnd參數(shù)所指定的窗口相關(guān)的且wMsgFilterMin和wMsgFilterMax參數(shù)所給出的消息值范圍內(nèi)的消息。需要注意的是,如果hWnd為NULL,則GetMessage獲取屬于調(diào)用該函數(shù)應(yīng)用程序的任一窗口的消息,如果wMsgFilterMin和wMsgFilterMax都是0,則GetMessage就返回所有可得到的消息。函數(shù)獲取之后將刪除消息隊(duì)列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT則只有在其處理之后才被刪除。,消息的處理,接下來(lái)我們談一下消息的處理,首先我們來(lái)看一下VC中的消息泵: while(GetMessage( } }首先,GetMessage從進(jìn)程的主線(xiàn)程的消息隊(duì)列中獲取一個(gè)消息并將它復(fù)制到MSG結(jié)構(gòu),如果隊(duì)列中沒(méi)有消息,則GetMessage函數(shù)將等待一個(gè)消息的到來(lái)以后才返回。然后TranslateAccelerator判斷該消息是不是一個(gè)按鍵消息并且是一個(gè)加速鍵消息,如果是,則該函數(shù)將把幾個(gè)按鍵消息轉(zhuǎn)換成一個(gè)加速鍵消息傳遞給窗口的回調(diào)函數(shù)。處理了加速鍵之后,函數(shù)TranslateMessage將把兩個(gè)按鍵消息WM_KEYDOWN和WM_KEYUP轉(zhuǎn)換成一個(gè)WM_CHAR,不過(guò)需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然將傳遞給窗口的回調(diào)函數(shù)。,消息的處理,處理完之后,DispatchMessage函數(shù)將把此消息發(fā)送給該消息指定的窗口中已設(shè)定的回調(diào)函數(shù)。如果消息是WM_QUIT,則GetMessage返回0,從而退出循環(huán)體。應(yīng)用程序可以使用PostQuitMessage來(lái)結(jié)束自己的消息循環(huán)。通常在主窗口的WM_DESTROY消息中調(diào)用。,窗口過(guò)程,窗口過(guò)程是一個(gè)用于處理所有發(fā)送到這個(gè)窗口的消息的函數(shù)。任何一個(gè)窗口類(lèi)都有一個(gè)窗口過(guò)程。同一個(gè)類(lèi)的窗口使用同樣的窗口過(guò)程來(lái)響應(yīng)消息。 系統(tǒng)發(fā)送消息給窗口過(guò)程將消息數(shù)據(jù)作為參數(shù)傳遞給他,消息到來(lái)之后,按照消息類(lèi)型排序進(jìn)行處理,其中的參數(shù)則用來(lái)區(qū)分不同的消息,窗口過(guò)程使用參數(shù)產(chǎn)生合適行為。 一個(gè)窗口過(guò)程不經(jīng)常忽略消息,如果他不處理,它會(huì)將消息傳回到執(zhí)行默認(rèn)的處理。窗口過(guò)程通過(guò)調(diào)用DefWindowProc來(lái)做這個(gè)處理。窗口過(guò)程必須return一個(gè)值作為它的消息處理結(jié)果。大多數(shù)窗口只處理小部分消息和將其他的通過(guò)DefWindowProc傳遞給系統(tǒng)做默認(rèn)的處理。窗口過(guò)程被所有屬于同一個(gè)類(lèi)的窗口共享,能為不同的窗口處理消息。,小結(jié),如果想在按下ESC鍵后,銷(xiāo)毀某一個(gè)窗口,則在窗口處理函數(shù)中,可以這樣寫(xiě): switch(uMsgId) { case WM_KEYDOWN: if (wParam==VK_ESCAPE) ::DestroyWindow(MainWndhandle); Return 0; } 該窗口沒(méi)有處理的消息交給默認(rèn)的窗口過(guò)程DefWindowProc處理。 用戶(hù)或者應(yīng)用程序的某些行為(調(diào)用一個(gè)API)產(chǎn)生一些事件,操作系統(tǒng)找到事件所屬的應(yīng)用程序,然后向該應(yīng)用程序發(fā)送一條相應(yīng)的消息。然后,該消息就被加入到該應(yīng)用程序的消息隊(duì)列中。之后,應(yīng)用程序不斷地檢查消息隊(duì)列。每當(dāng)接受到一條消息時(shí),應(yīng)用程序就會(huì)將該消息發(fā)給與該消息所屬窗口相關(guān)的窗口過(guò)程。最后,窗口過(guò)程執(zhí)行與當(dāng)前消息對(duì)應(yīng)的指令。,Window程序的運(yùn)行機(jī)制,基本上是這樣運(yùn)行的,程序從WinMain()開(kāi)始,然后進(jìn)入一個(gè)message loop,程序在這里等待發(fā)給它的所有消息然后一一處理,直到接收到WM_QUIT的消息的時(shí)候,message loop終止,程序結(jié)束。所以整個(gè)主程序運(yùn)行的過(guò)程就是等待消息,接收消息,然后處理消息的過(guò)程。,,理解Window編程所使用的事件驅(qū)動(dòng)模型,Windows程序基本框架 Windows程序具有相對(duì)固定的結(jié)構(gòu)。與以前的DOS程序不同。Windows程序和操作系統(tǒng)結(jié)合更緊密。可以說(shuō)應(yīng)用程序的在運(yùn)行時(shí)絕大多數(shù)時(shí)間都在等待操作系統(tǒng)的消息。我們編寫(xiě)一個(gè)Windows程序其實(shí)很簡(jiǎn)單。需要做的工作是:注冊(cè)窗口類(lèi),創(chuàng)建窗口對(duì)象,編寫(xiě)窗口過(guò)程,消息循環(huán)。,,1:注冊(cè)窗口類(lèi),Windows的窗口類(lèi)定義了一個(gè)窗口的風(fēng)格,而類(lèi)中定義的窗口過(guò)程決定了窗口的行為。每個(gè)類(lèi)都有一個(gè)自己的名字,在Windows中所有的窗口都屬于一個(gè)窗口類(lèi)。如果我們需要?jiǎng)?chuàng)建一個(gè)自己的窗口,則必須注冊(cè)一個(gè)窗口類(lèi)。Win32系統(tǒng)提供了一些全局類(lèi)。這些類(lèi)無(wú)需注冊(cè)就可以使用。比如:Windows的一些通用控件。對(duì)話(huà)框類(lèi)。等等。下面是一個(gè)注冊(cè)窗口類(lèi)的代碼: WNDCLASS wc; memset( 上面的代碼 WNDCLASS 是一個(gè)結(jié)構(gòu)體,我們通過(guò)設(shè)置它的成員的值來(lái)設(shè)定窗口類(lèi)的風(fēng)格和屬性。然后將這個(gè)結(jié)構(gòu)體傳遞給系統(tǒng),申請(qǐng)注冊(cè)窗口類(lèi)。成功返回非0值,失敗返回0.如果注冊(cè)成功。我們就可以利用該類(lèi)名來(lái)創(chuàng)建窗口了。,2:注冊(cè)窗口類(lèi),創(chuàng)建窗口就比較簡(jiǎn)單了。我們只需要調(diào)用CreateWindow函數(shù),就可以創(chuàng)建它。用戶(hù)要注意的是,在這里要了解每個(gè)參數(shù)的作用。 HWND CreatemdiWndClassWnd(void) { HWND hwnd=CreateWindow(“MyWndClass”,“MDI 多文檔”,//這兩個(gè)參數(shù),第一個(gè)為類(lèi)名,就是我們前面注冊(cè)的窗口類(lèi)名,第二個(gè)為窗口標(biāo)題 。 WS_MINIMIZEBOX|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZEBOX|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_THICKFRAME,//這里是窗口風(fēng)格,我們可以在這里指定窗口是否有最大化按鈕,是否有標(biāo)題欄,是否可調(diào)整邊框等等一些風(fēng)格 CW_USEDEFAULT,0,CW_USEDEFAULT,0,//這里是指定窗口的坐標(biāo)和尺寸 NULL, NULL, hInst,//實(shí)例句柄 NULL); ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; return hwnd; } 通過(guò)上面這個(gè)函數(shù),我們已經(jīng)創(chuàng)建了一個(gè)窗口,創(chuàng)建完畢后還不能顯示,需要調(diào)用ShowWindow()函數(shù)窗口就會(huì)正常顯示出來(lái)。 在返回前,CreateWindow給窗口過(guò)程發(fā)送一個(gè)WM_CREATE消息。對(duì)于層疊,彈出式和子窗口,CreateWindow給窗口發(fā)送WM_CREATE,WM_GETMINMAXINFO和WM_NCCREATE消息。消息WM_CREATE的IParam參數(shù)包含一個(gè)指向CREATESTRUCT結(jié)構(gòu)的指針。如果指定了WS_VISIBLE風(fēng)格,CreateWindow向窗口發(fā)送所有需要激活和顯示窗口的消息。,3:窗口過(guò)程,窗口過(guò)程是我們處理消息的關(guān)鍵。前面我們說(shuō)過(guò),我們的應(yīng)用程序的大部分工作都由操作系統(tǒng)完成,我們只要對(duì)自己感興趣的事件處理即可。在注冊(cè)窗口類(lèi)的一節(jié)我們看到過(guò)了。窗口過(guò)程是一個(gè)函數(shù),它在注冊(cè)窗口類(lèi)的時(shí)候被傳遞。 LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { switch (msg) { case WM_CREATE: //這里是窗口創(chuàng)建完畢的消息,每一個(gè)窗口創(chuàng)建完畢都會(huì)產(chǎn)生次事件 //do something 做我們需要做的工作。完了要break; break; case WM_CLOSE://當(dāng)用戶(hù)點(diǎn)擊關(guān)閉按鈕的時(shí)候會(huì)觸發(fā)這個(gè)事件。 DestroyWindow(hWin); return TRUE; case WM_DESTROY: PostQuitMessage(NULL); break; default: return DefWindowProc(hWin,uMsg,wParam,lParam);//我說(shuō)了。大部分工作由系統(tǒng)處理吧,不感興趣的消息。統(tǒng)統(tǒng)交給默認(rèn)窗口過(guò)程。 } return 0; },窗口過(guò)程,上面的窗口過(guò)程很簡(jiǎn)單吧。窗口過(guò)程是一個(gè)回調(diào)函數(shù),也就是說(shuō)。它是由操作系統(tǒng)調(diào)用的。當(dāng)我們點(diǎn)擊一個(gè)鼠標(biāo)或者按下一個(gè)鍵后,操作系統(tǒng)會(huì)將消息發(fā)送給前臺(tái)窗口,應(yīng)用程序接收到此消息后,會(huì)調(diào)用對(duì)應(yīng)的窗口過(guò)程。這個(gè)時(shí)候窗口過(guò)程被執(zhí)行。 響應(yīng)WM_DESTROY,調(diào)用PostQuitMessage(int)結(jié)束進(jìn)程。它會(huì)投遞一個(gè)WM_QUIT消息對(duì)消息隊(duì)列中。當(dāng)消息循環(huán)的GetMessage取到WM_QUIT消息,則返回0,程序結(jié)束。 所以說(shuō)應(yīng)用程序會(huì)自己產(chǎn)生消息。,4:消息循環(huán),消息循環(huán)顧名思義,就是循環(huán)等待消息的到來(lái)。 while (GetMessage ( 這里是一個(gè)最簡(jiǎn)單的消息循環(huán)了。GetMessage 是從消息隊(duì)列種取得一條消息,如果消息隊(duì)列中沒(méi)有消息,這個(gè)函數(shù)就等待,直到有消息到達(dá)才會(huì)返回。當(dāng)然如果收到WM_QUIT 消息,這個(gè)函數(shù)會(huì)返回假,循環(huán)跳出,這個(gè)時(shí)候就宣告應(yīng)用程序關(guān)閉了。窗口過(guò)程中的 PostQuitMessage() 就是發(fā)送這個(gè)消息。通知退出消息循環(huán)。TranslateMessage () 函數(shù)的功能是對(duì)一些原始消息進(jìn)行預(yù)處理,比如按鍵消息DispatchMessage ()函數(shù)則是負(fù)責(zé)分派消息,它會(huì)將消息的參數(shù)做為調(diào)用參數(shù),調(diào)用該窗口的窗口過(guò)程。,WinMain函數(shù),WinMain函數(shù)是所有windows應(yīng)用程序的入口,類(lèi)似于C語(yǔ)言中的Main函數(shù),其功能是完成一系列的定義和初始化工作,并產(chǎn)生消息循環(huán)。消息循環(huán)是整個(gè)程序運(yùn)行的核心。WinMain函數(shù)實(shí)現(xiàn)以下功能。 1. 注冊(cè)窗口類(lèi),建立窗口及執(zhí)行其它必要的初始化工作; 2. 進(jìn)入消息循環(huán),根據(jù)從應(yīng)用程序消息隊(duì)列接受的消息,調(diào)用相應(yīng)的處理過(guò)程 3. 當(dāng)消息循環(huán)檢索到WM_QUIT消息時(shí)終止程序運(yùn)行。 WinMain函數(shù)有三個(gè)基本的組成部份:函數(shù)說(shuō)明、初始化和消息循環(huán)。 WinMain函數(shù)的說(shuō)明如下: int WINAPI WinMain( //WinMain函數(shù)說(shuō)明 HINSTANCE hInstance, //程序當(dāng)前實(shí)例句柄 HINSTANCE hPrevInstance, //應(yīng)用程序其它實(shí)例句柄 LPSTR lpCmdLine, //指向程序命令行參數(shù)的指針 int nCmdShow //應(yīng)用程序開(kāi)始執(zhí)行時(shí)窗口顯示方式的整數(shù)值標(biāo)識(shí) ) 由于Window操作系統(tǒng)是多任務(wù)的操作系統(tǒng),能進(jìn)行多任務(wù)的管理,因此,windows應(yīng)用程序可能被并行的多次執(zhí)行,因而可能出現(xiàn)同一個(gè)程序的多個(gè)窗口同時(shí)存在的情況,Windows系統(tǒng)將應(yīng)用程序每一次執(zhí)行稱(chēng)為該應(yīng)用程序的一個(gè)實(shí)例(Instance),并用一個(gè)實(shí)例句柄唯一的標(biāo)識(shí)它。 #define WINAPI _stdcall,指定函數(shù)的調(diào)用約定,即函數(shù)參數(shù)的壓棧順序,由調(diào)用者還是被調(diào)用者把參數(shù)彈出棧,以及產(chǎn)生函數(shù)修飾名的方法。,HelloWORLD示例程序的解釋,int APIENTRY WinMain(HINSTANCE hInstance, //WinMain函數(shù)說(shuō)明 HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. /* 建議采用Pascal的變量定義風(fēng)格,即在程序(函數(shù))開(kāi)始處定義所有變量 雖然C++的變量定義比較靈活,本程序?yàn)榱耸钩绦蛞子诶斫?未采用這種方法,便于移植。 */ char lpszClassName[]=“窗口“; //窗口類(lèi)名 char lpszTitle[]=“Windows SDK編程之一 窗口示例程序“; //窗口標(biāo)題名 //---------------窗口類(lèi)定義------------------------------------- /* 窗口類(lèi)的定義 在Windows應(yīng)用程序中,窗口害定義了窗口的形式與功能。窗口類(lèi)定義通過(guò)給窗口類(lèi)數(shù)據(jù)結(jié)構(gòu)WNDCLASS賦值完成,該數(shù)據(jù)結(jié)構(gòu)中包括窗口類(lèi)的各種屬性,在窗口類(lèi)定義過(guò)程中常用到以下函數(shù): */,WNDCLASS wndclass; wndclass.style=0; //窗口類(lèi)型為缺省類(lèi)型 wndclass.lpfnWndProc=WndProc; //窗口處理函數(shù)為WndProc wndclass.cbClsExtra=0; //窗口類(lèi)無(wú)擴(kuò)展 wndclass.cbWndExtra=0; //窗口實(shí)例無(wú)擴(kuò)展 wndclass.hInstance=hInstance; //當(dāng)前實(shí)例句柄 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); //使用缺省圖標(biāo) /* LoadIcon():在應(yīng)用程序中加載一個(gè)窗口圖標(biāo) LoadIcon()函數(shù)原型為: HICON LoadIcon( HINSTANCE hInstance,//圖標(biāo)資源所在的模塊句柄,為NULL則使用系統(tǒng)預(yù)定義圖標(biāo) LPCTSTR lpIconName //圖標(biāo)資源名或系統(tǒng)預(yù)定義圖標(biāo)標(biāo)識(shí)名 )*/,實(shí)例,實(shí)例,wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); //窗口采用箭頭光標(biāo) /* LoadCursor():在應(yīng)用程序中加載一個(gè)窗口光標(biāo) LoadCursor()函數(shù)原型為: HCURSOR LoadCursor( HINSTANCE hInstance,//光標(biāo)資源所在的模塊句柄,為NULL則使用系統(tǒng)預(yù)定義光標(biāo) LPCTSTR lpCursorName //光標(biāo)資源名或系統(tǒng)預(yù)定義光標(biāo)標(biāo)識(shí)名 ) */ wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //窗口背景為白色 /* GetStockObject():獲取已經(jīng)定義的畫(huà)筆、畫(huà)刷、字體等對(duì)象的句柄 GetStockObject()函數(shù)原型為: HGDIOBJ GetStockObject(int fnObject); //fnObject為對(duì)象的標(biāo)識(shí)名 */ wndclass.lpszMenuName=NULL; //窗口中無(wú)菜單 wndclass.lpszClassName=lpszClassName; //窗口類(lèi)名為'窗口實(shí)例',實(shí)例,//------------------以下是進(jìn)行窗口類(lèi)的注冊(cè)--------------------------- /* 注冊(cè)窗口類(lèi) Windows系統(tǒng)本身提供部份預(yù)定義的窗口類(lèi),程序員也可以自定義窗口類(lèi),窗口類(lèi)必須先注冊(cè)后使用。窗口類(lèi)的注冊(cè)由注冊(cè)函數(shù)RegisterClass()實(shí)現(xiàn)。其形式為: RegisterClass( //指向一個(gè)傳遞給窗口的參數(shù)值的指針*/,實(shí)例,//創(chuàng)建窗口操作 HWND hwnd; //窗口結(jié)構(gòu) hwnd=CreateWindow(lpszClassName, //創(chuàng)建窗口,窗口類(lèi)名 lpszTitle, //窗口實(shí)例的標(biāo)題名 WS_OVERLAPPEDWINDOW, //窗口的風(fēng)格 CW_USEDEFAULT,CW_USEDEFAULT, //窗口左上角坐標(biāo)為缺省值 CW_USEDEFAULT,CW_USEDEFAULT, //窗口的高度和寬度為缺省值 NULL, //此窗口無(wú)父窗口 NULL, //此窗口無(wú)主菜單 hInstance, //應(yīng)用程序當(dāng)前句柄 NULL); //不使用該值 ShowWindow(hwnd,nCmdShow); //顯示窗口 UpdateWindow(hwnd); //繪制用戶(hù)區(qū),實(shí)例,/* 消息循環(huán) windows應(yīng)用程序的運(yùn)行以消息為核心。windows將產(chǎn)生的消息放入應(yīng)用程序的消息隊(duì)列中而應(yīng)用程序WinMain函數(shù)的消息循環(huán)提取消息隊(duì)列中的消息,并將其傳遞給窗口函數(shù)為相應(yīng)處理過(guò)程處理。 MSG msg; //消息結(jié)構(gòu) while( GetMessage( * /,實(shí)例,while( GetMessage( //程序終止時(shí),將信息返回操作系統(tǒng) },實(shí)例,//-----------------------------窗口函數(shù)--------------------------------------- /* 窗口消息處理函數(shù)定義了應(yīng)用程序?qū)邮盏降牟煌⒌捻憫?yīng),它包含了應(yīng)用程序?qū)Ω鞣N可用接收到的消息的處理過(guò)程,通常 ,窗口函數(shù)由一個(gè)或多個(gè)switch.case語(yǔ)句組成,每一條case語(yǔ)句 對(duì)應(yīng)一種消息,當(dāng)應(yīng)用程序接收到一個(gè)消息時(shí),相應(yīng)的case語(yǔ)句被 激活并執(zhí)行相應(yīng)的響應(yīng)程序模塊。 窗口函數(shù)的一般形式如下: LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); Parameters hwnd :[in] Handle to the window. uMsg :[in] Specifies the message. wParam:[in] Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter. lParam:[in] Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter.,實(shí)例,Return Value The return value is the result of the message processing and depends on the message sent. LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { switch (message) { case . break; . case WM_DESTROY: //void PostQuitMessage(int nExitCode)函數(shù)的作用是向程序發(fā)送WM_QUIT消息,nExitCode應(yīng)用程序退出代碼 PostQuitMessage(0); //調(diào)用該函數(shù)發(fā)出WM_QUIT消息 default: //缺省消息處理函數(shù),以保證所的發(fā)往窗口的消息都能被處理 return DefWindowProc(hwnd,message,wParam,lParam); } return (0); */,示例,LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); //調(diào)用該函數(shù)發(fā)出WM_QUIT消息 default: //缺省消息處理函數(shù) return DefWindowProc(hwnd,message,wParam,lParam); } return (0); } /*注: 事件驅(qū)動(dòng)的特點(diǎn): Windows程序設(shè)計(jì)圍繞著事件或消息的產(chǎn)生驅(qū)動(dòng)產(chǎn)生運(yùn)行消息處理函數(shù)。Windows程序的執(zhí)行順序取決于事件發(fā)生的順序,程序的執(zhí)行是由順序產(chǎn)生的消息驅(qū)動(dòng)的,程序員可以針對(duì)消息類(lèi)型編寫(xiě)消息處理程序以處理接收的消息,或者發(fā)出其他消息以驅(qū)動(dòng)其他處理程序,但是不必預(yù)先確定消息的產(chǎn)生順序。這是面向?qū)ο缶幊讨惺录?qū)動(dòng)的顯著特點(diǎn)。 事件驅(qū)動(dòng)編程方法對(duì)于編寫(xiě)交互程序很有用處,用這一方法編寫(xiě)的程序使程序避免了死板的操作模式,從而使用戶(hù)能夠按照自己的意愿采用靈活多變的操作模式。 Windows應(yīng)用程序中的消息傳遞機(jī)制: VC中存在幾種系統(tǒng)定義的消息分類(lèi),常用的消息由窗口消息、初始化消息、輸入消息、系統(tǒng)消息、剪切板消息、文當(dāng)界面消息、DDE(動(dòng)態(tài)數(shù)據(jù)交換)消息、應(yīng)用程序自定義消息等。應(yīng)用程序- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來(lái)的問(wèn)題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
14.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁(yè)顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開(kāi)word文檔。
- 特殊限制:
部分文檔作品中含有的國(guó)旗、國(guó)徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- Windows 應(yīng)用程序 基本 結(jié)構(gòu)
鏈接地址:http://m.hcyjhs8.com/p-1906271.html