BOOLInitWindowsClass(HINSTANCEhInstance);//注冊(cè)窗口類BOOLInitWindows(HINSTANCEhInstance,intnCmdShow);//創(chuàng)建窗口LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);//窗口函數(shù)聲明HWNDhMainWnd;//全局實(shí)例窗口句柄LPCTSTRlpszProviderClass=__TEX" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Windows編程之SDK窗口程序淺析

系統(tǒng) 2044 0

Windows編程之SDK窗口程序淺析

SDK 編寫 Windows 程序需完成 3 個(gè)框架模塊:

<1> 填空賦值 WNDCLASS 定義窗口類并注冊(cè);

<2> 創(chuàng)建窗口,顯示、刷新窗口;

<3> 消息循環(huán),編寫消息處理函數(shù)。

熟悉框架后,我們的重點(diǎn)工作放在感興趣的消息處理上。

有以上分析可分模塊完成注冊(cè)窗口類和創(chuàng)建窗口工作,即分別設(shè)計(jì)功能函數(shù) InitWindowsClass InitWindows ,改造后的完整程序如下,從以下程序可以更清楚的認(rèn)識(shí) windows 程序框架。

Windows 窗口應(yīng)用程序與 DOS 控制臺(tái)應(yīng)用程序是不同的,編寫一個(gè)基于 Windows API 的典型的應(yīng)用程序需要編寫處理以下四個(gè)任務(wù):

l 初始化

l 實(shí)例化

l 啟動(dòng)消息循環(huán)

l 響應(yīng)消息

前面三個(gè)任務(wù)總是發(fā)生在 WinMain 函數(shù)中, WinMain 是每一個(gè) Windows 程序的入口點(diǎn),相當(dāng) C/C++ 中的 main 。第四個(gè)任務(wù)是傳統(tǒng)上稱為 WndProc 的函數(shù)來承擔(dān)的。

1 .初始化(注冊(cè)窗口類,創(chuàng)建窗口)

要定義一個(gè)窗口類 struct WNDCLASS WndClass ; 該數(shù)據(jù)結(jié)構(gòu)實(shí)際存儲(chǔ)的是一個(gè)窗口的屬性集。 調(diào)用 ATOM RegisterClass ( CONST WNDCLASSW * lpWndClass ); 函數(shù)注冊(cè) lpWndClass 指向的窗口類模板。窗口類是一個(gè)內(nèi)核對(duì)象,不同的窗口類以名稱( WNDCLASS lpszClassName 字段)區(qū)分。

例如后面 MFC 中的 AfxRegisterClass 函數(shù)中,注冊(cè)窗口類前先調(diào)用 GetClassInfo 函數(shù)檢測預(yù)注冊(cè)的窗口類是否已注冊(cè)。 GetClassInfo 函數(shù)用來獲取指定名稱的窗口類信息,其原型如下:

BOOL GetClassInfo ( HINSTANCE hInstance , LPCTSTR lpClassName , LPWNDCLASSW lpWndClass );

以下為 AfxRegisterClass 函數(shù)代碼片段:

// WINCORE.CPP

BOOL AFXAPI AfxRegisterClass ( WNDCLASS * lpWndClass )

{

WNDCLASS wndcls ;

if ( GetClassInfo ( lpWndClass -> hInstance , lpWndClass -> lpszClassName , & wndcls ))

{

// class already registered

return TRUE ;

}

if (!:: RegisterClass ( lpWndClass ))

{

TRACE1 ("Can't register window class named %s/n",

lpWndClass -> lpszClassName );

return FALSE ;

}

//……

}

對(duì)于一個(gè)已注冊(cè)的窗口類,可調(diào)用 BOOL UnregisterClass ( LPCTSTR lpClassName , HINSTANCE hInstance ); 函數(shù)進(jìn)行注銷。

以下為 Win32SDK 示例程序中的注冊(cè)窗口類、創(chuàng)建窗口的代碼片段:

lpszProviderClass = __TEXT( " MyWndClass ") ;

WndClass . lpszClassName = lpszProviderClass ;

然后給定義窗口風(fēng)格以及用于該窗口類的消息處理函數(shù)。然后 CreateWindow lpszProviderClass ,……)將使用名稱為 lpszProviderClass 的窗口類 WndClass 作為模版創(chuàng)建類的實(shí)例。

在調(diào)用 CreateWindow(Ex) 時(shí),第一個(gè)參數(shù)也可以直接使用系統(tǒng)預(yù)定義( Predefined )的子窗口控件類,例如 "BUTTON" "EDIT" "COMBOBOX" 等這些是系統(tǒng)內(nèi)部已注冊(cè)的 WNDCLASS ,免去調(diào)用 RegisterClass

創(chuàng)建窗口后,調(diào)用 GetClassName 函數(shù)獲取指定窗口 hWnd 所使用的窗口類名稱。其函數(shù)原型如下:

int GetClassName ( HWND hWnd , LPTSTR lpClassName , int nMaxCount );

2 .實(shí)例化(顯示窗口,刷新窗口)

一旦窗口被創(chuàng)建,還需要完成若干步才能運(yùn)行你的程序。首先,當(dāng)一個(gè)窗口被創(chuàng)建時(shí),它通常是不可見的,一般要調(diào)用 BOOL ShowWindow ( HWND hWnd , int nCmdShow ); 函數(shù) 來顯示窗口,調(diào)用 BOOL UpdateWindow ( HWND hWnd ); 函數(shù)來刷新窗口。

函數(shù) UpdateWindow 向窗口 hWnd 發(fā)送第一個(gè) WM_PAINT 消息以更新它的客戶區(qū)。當(dāng) ShowWindow 使窗口顯示在屏幕上時(shí),窗口的客戶區(qū)會(huì)被 WndClass . hbrBackground 擦除,調(diào)用 UpdateWindow 函數(shù)將促使客戶區(qū)重繪,以顯示其內(nèi)容。

3 .消息循環(huán)

1 )消息的產(chǎn)生

無論用戶移動(dòng)鼠標(biāo)或按下某個(gè)鍵, Windows 系統(tǒng)將創(chuàng)建一個(gè)消息(對(duì)應(yīng)數(shù)據(jù)結(jié)構(gòu)為 MSG )并將之投放到對(duì)應(yīng)窗口 (MSG.hwnd 指標(biāo) ) 所在線程的消息隊(duì)列中。

2 )獲取消息

應(yīng)用程序調(diào)用 GetMessage 函數(shù)從調(diào)用線程消息隊(duì)列中取出 (pop) 消息。

GetMessage 函數(shù)原型如下:

BOOL GetMessage ( LPMSG lpMsg, HWND hWnd , UINT wMsgFilterMin, UINT wMsgFilterMax);

取出的消息存放至參數(shù)一 lpMsg 所指內(nèi)存(本地聲明的 MSG 結(jié)構(gòu)體變量)。

參數(shù)二 hWnd 標(biāo)識(shí)要檢查消息的窗口,如果為 NULL ,則獲取屬于調(diào)用線程消息隊(duì)列中任一(窗口)消息;如果不為 NULL ,則只獲取指定窗口的消息。

wMsgFilterMin wMsgFilterMax 指定獲取消息碼的范圍。一般將兩參數(shù)都置零,表示無消息 ID 范圍限制。

注意該函數(shù)是阻塞的,直到有一個(gè)( hWnd 的)消息到來,它才返回。如果消息為 WM_QUIT ,則該函數(shù)返回 FALSE ,結(jié)束消息循環(huán);否則返回 TRUE ,繼續(xù)下一輪消息循環(huán)。

<1> 等待消息

函數(shù) BOOL WaitMessage ( VOID ); 使調(diào)用線程掛起,直到一個(gè)新的消息放到調(diào)用線程消息隊(duì)列中才返回。

<2> 取出消息

函數(shù) PeekMessage 查看調(diào)用線程消息隊(duì)列中(指定窗口 hWnd )是否有消息。如果有消息則取出放入 lpMsg 所指 MSG 結(jié)構(gòu)體中,返回 TRUE ;如果無(指定窗口 hWnd 的)消息則立即退出(即非阻塞),返回 FALSE 。其函數(shù)原型如下:

BOOL PeekMessage ( LPMSG lpMsg , HWND hWnd , UINT wMsgFilterMin , UINT wMsgFilterMax , UINT wRemoveMsg );

前四個(gè)參數(shù)同 GetMessage wRemoveMsg 參數(shù)指定當(dāng)有消息讀取消息后,是否從消息隊(duì)列中移除該消息。其為下列值之一:

PM_NOREMOVE: 讀取后消息依然留在隊(duì)列中;

PM_REMOVE: 讀取后消息從隊(duì)列中移除;

<3> GetMessage = WaitMessage + PeekMessage ( PM_REMOVE )

3 )翻譯消息

如果輸入列表中有一個(gè)屬于你的應(yīng)用程序的消息,并且是按鍵消息時(shí), TranslateMessage 將虛擬鍵消息轉(zhuǎn)換為字符消息( WM_KEYDOWN + WM_KEYUP = WM_CHAR WM_SYSKEYDOWN + WM_SYSKEYUP = WM_SYSCHAR ),再將字符消息( WM_CHAR WM_SYSCHAR )投遞到調(diào)用線程的消息隊(duì)列中。

TranslateMessage 函數(shù)內(nèi)部機(jī)制大致如下:

BOOL TranslateMessage ( CONST MSG * lpMsg )

{

if ( lpMsg -> message == WM_KEYDOWN || lpMsg -> message == WM_SYSKEYDOWN )

{

UINT message ;

if ( lpMsg -> message == WM_KEYDOWN )

{

message = WM_CHAR ;

}

else if ( lpMsg -> message == WM_SYSKEYDOWN )

{

message = WM_SYSCHAR ;

}

PostMessage ( lpMsg -> hwnd , message , lpMsg -> wParam , lpMsg -> lParam );

return TRUE ; // 消息被轉(zhuǎn)換

}

return FALSE ;

}

4 )路由消息

取出消息后,需要進(jìn)行處理。應(yīng)用程序調(diào)用 DispatchMessage 函數(shù) 將取得的消息發(fā)送到窗口消息處理函數(shù) WndProc WndProc 采用 switch-case 分支結(jié)構(gòu)對(duì)不同的消息不同的響應(yīng)處理。

WndProc WNDPROC 函數(shù)指針,其類型如下:

typedef LRESULT ( CALLBACK * WNDPROC )( HWND , UINT , WPARAM , LPARAM );

DispatchMessage 函數(shù)內(nèi)部機(jī)制大致如下:

LRESULT DispatchMessage ( CONST MSG * lpMsg )

{

// 根據(jù) lpMsg->hwnd 查找用于創(chuàng)建該窗口的 WNDCLASS CreateWindow lpClassName 指定)的 lpfnWndProc;

CallWindowProc ( lpfnWndProc , lpMsg -> hwnd , lpMsg -> message , lpMsg -> wParam , lpMsg -> lParam );

}

4 .消息處理

Windows 編程中常見的消息有:窗口創(chuàng)建消息 WM_CREATE, 窗口繪制消息 WM_PAINT ,按鍵消息 WM_KEYDOWN, WM_CHAR, 窗口關(guān)閉消息 WM_CLOSE ,窗口銷毀消息 WM_DESTROY ,退出應(yīng)用程序消息 WM_QUIT 等。

默認(rèn)情況下,關(guān)閉窗口的處理流程如下:

點(diǎn)擊關(guān)閉按鈕 à 系統(tǒng)向指定窗口發(fā)送 WM_CLOSE 消息 à WM_CLOSE 消息響應(yīng)中調(diào)用 DestroyWindow 向窗口發(fā)送 WM_DESTROY 消息 à WM_DESTROY 消息響應(yīng)中調(diào)用 PostQuitMessage 向窗口發(fā)送 WM_QUIT 消息結(jié)束窗口所屬線程的消息循環(huán)( GetMessage 函數(shù)返回), 終止窗口所屬線程。

實(shí)際應(yīng)用軟件在響應(yīng)關(guān)閉消息時(shí)通常將窗口最小化(到托盤),并不真正關(guān)閉。應(yīng)用程序?qū)⒃跊]有窗口的條件下繼續(xù)運(yùn)行。

參考 窗口破 過程與Windows 消息循環(huán) WM_CLOSE 、WM_DESTROY 和WM_QUIT 三者的區(qū)別

每個(gè) Windows 程序(進(jìn)程)都至少包含一個(gè)窗口和一個(gè)應(yīng)用程序的實(shí)例,在程序中表現(xiàn)為窗口句柄 hWnd 和實(shí)例句柄 hInstance. 我們可以透過以下幾條程序語句一窺 Windows 程序運(yùn)行機(jī)制:

WndClass.hInstance= hInstance ; // 這一賦值表明要注冊(cè)的窗口類屬于當(dāng)前實(shí)例

ShowWindow( hWnd ,nCmdShow); UpdateWindow( hWnd ); // 顯示刷新該程序窗口

GetMessage // 提取消息隊(duì)列中的消息

TranslateMessage(& Msg ); // 翻譯消息,該函數(shù)負(fù)責(zé)將消息的虛擬鍵轉(zhuǎn)換成字符消息

DispatchMessage(& Msg ); // 將參數(shù) lpMSG 標(biāo)識(shí)的消息發(fā)送給窗口函數(shù) WndProc

switch( nMessage ) case: // 按接受到的消息值 nMessage 判斷是哪一種消息并處理

以下為 Windows 應(yīng)用程序執(zhí)行流程圖:

Windows編程之SDK窗口程序淺析


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 久久综合九色综合欧洲 | 色综合综合色综合色综合 | 国产欧美亚洲精品第3页在线 | 欧美人牲囗毛片 | 精品综合久久久久97 | 91蝌蚪在线播放 | 国产欧美一区二区精品久久久 | 成人网18免费网站在线 | 日本在线不卡免费视频一区 | 99久久中文字幕伊人情人 | 性一级视频 | 国产成人精品视频一区 | 精品国产综合区久久久久久 | 欧美精品在线免费观看 | 欧美激情_区二区三区 | 免费观看欧美一级毛片 | 日韩字幕无线乱码 | 一区二区三区四区产品乱码伦 | 天天爱天天做久久天天狠狼 | 天天综合网在线 | 手机看片福利日韩国产 | 久久久国产乱子伦精品 | 性夜影院爽黄a爽免费看网站 | 九九51精品国产免费看 | 亚洲精品乱码久久久久久蜜桃欧美 | 嫩模尺度私拍在线视频 | 国产99热在线观看 | 日日拍夜夜嗷嗷叫狠狠 | 成人精品一区二区三区中文字幕 | 亚洲图色视频 | 99热免费| 久久精品国产一区二区三区 | 国产一级毛片夜一级毛片 | 日日摸夜夜添夜夜添欧美毛片 | 亚洲视频色 | 91视频亚洲 | 99国产精品一区二区 | 亚洲精品久久久久中文 | 国语性猛交xxxx乱大交 | 久久国产精品国产自线拍免费 | 国产国拍亚洲精品午夜不卡17 |