windows窗口與消息

 

windows編程(窗口與消息)

窗口是屏幕上的矩形區域,消息窗口功能有限,因爲我們不能添加四個以上的按鈕以及菜單等,而且添加的按鈕必須是windows提供的按鈕,不能自定義。所以我們有必要自己創建一個多功能可自定義的窗口。

自己的窗口

創建窗口最重要的函數是CreateWindow,它可以創建重疊式窗口,彈出式窗口,子窗口等。而且可以自定義各種功能。

HWND CreateWindow(     

    LPCTSTR lpClassName, //窗口類

    LPCTSTR lpWindowName,

    DWORD dwStyle,

    int x,

    int y,

    int nWidth,

    int nHeight,

    HWND hWndParent,

    HMENU hMenu,

    HINSTANCE hInstance,

    LPVOID lpParam 

);

從函數原型可以看出創建窗口的各種屬性,一種窗口含有顯示程序名稱的標題列、菜單甚至可能還有工具列和滾動條,另一種窗口是對話框,在上面可以放置各種控件。而這些控件也是窗口,稱爲子窗口。

窗口消息處理程序

窗口處理函數是理解消息機制的關鍵,windows處理將消息循環中取得的各種消息放入這個函數中進行處理,該函數會比對各個匹配項直到找到對應的處理項,如果沒有找到就傳給一個默認的窗口函數,是程序正常結束。該函數可以在程序中也可以在dll中。使用窗口類使多個窗口能夠屬於同一個窗口類,並使用同一個窗口消息處理函數。

HELLOWIN程序

//===========================

//  (c)狗尾草 2008.1.19

//===========================

#include<windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)

{

 static TCHAR szAppName[]="HelloWin";

 HWND hWnd;

 MSG msg;

 WNDCLASS wndclass;

 wndclass.cbClsExtra=0;

 wndclass.cbWndExtra=0;

 wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

 wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);

 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

 wndclass.hInstance=hInstance;

 wndclass.lpfnWndProc=WndProc;

 wndclass.lpszClassName=szAppName;

 wndclass.lpszMenuName=NULL;

 wndclass.style=CS_HREDRAW|CS_VREDRAW;

 if(!RegisterClass(&wndclass))

 {

  MessageBox(NULL,"This program requires windows nt!",szAppName,MB_ICONERROR);

  return 0;

 }

 hWnd=CreateWindow(szAppName,

  "The Hello Program!",

  WS_OVERLAPPEDWINDOW,

  CW_USEDEFAULT,

  CW_USEDEFAULT,

  CW_USEDEFAULT,

  CW_USEDEFAULT,

  NULL,

  NULL,

  hInstance,

  NULL);

 ShowWindow(hWnd,iCmdShow);

 UpdateWindow(hWnd);

 while(GetMessage(&msg,NULL,0,0))

 {

  TranslateMessage(&msg);

  DispatchMessage(&msg);

 }

 return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

 HDC hdc;

 PAINTSTRUCT ps;

 RECT rect;

 switch(message)

 {

 case WM_CREATE:

  return 0;

 case WM_PAINT:

  hdc=BeginPaint(hWnd,&ps);

  GetClientRect(hWnd,&rect);

  DrawText(hdc,"Hello,WindowsXP!",

           -1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);

  EndPaint(hWnd,&ps);

  return 0;

 case WM_DESTROY:

  PostQuitMessage(0);

  return 0;

 }

return DefWindowProc(hWnd,message,wParam,lParam);

}

調用的函數和功能如下,絕大多數在winuser.h:

LoadIcon

 加載圖標供程序使用

LoadCursor

加載鼠標光標供程序使用

GetStockObject

 取得一個圖形對象

RegisterClass

 爲程序窗口註冊窗口類別

MessageBox

顯示消息框

CreateWindow

 根據窗口類別建立一個窗口

ShowWindow

 在屏幕上顯示窗口

UpdateWindow

 指示窗口自我更新

GetMessage

 從消息隊列中取得消息

TranslateMessage

轉譯某些鍵盤消息

DispatchMessage

 將消息發送給窗口消息處理程序

PlaySound

播放一個聲音文件

BeginPaint

 開始繪製窗口

GetClientRect

取得窗口顯示區域的大小

DrawText

 顯示字符串

EndPaint

 結束繪製窗口

PostQuitMessage

 在消息隊列中插入一個「退出程序」消息

DefWindowProc

 執行內定的消息處理

關於一些常量定義的約定如下:

前綴

類別

CS

窗口類別樣式

CW

建立窗口

DT

繪製文字

IDI

圖示ID

IDC

遊標ID

MB

消息框

SND

聲音

WM

窗口消息

WS

窗口樣式

常數值是沒有必要記憶的,記住常量的一些大寫標識符就可以了。

各種句柄

標識符

含義

HINSTANCE

執行實體(程序自身)句柄

HWND

窗口句柄

HDC

設備內容句柄

句柄通常是調用函數取得的,起到一個標識身份的目的。其實實質是一個32位整數。

數據結構註解

窗口類結構

typedef struct {

    UINT cbSize;

    UINT style;

    WNDPROC lpfnWndProc;

    int cbClsExtra;

    int cbWndExtra;

    HINSTANCE hInstance;

    HICON hIcon;

    HCURSOR hCursor;

    HBRUSH hbrBackground;

    LPCTSTR lpszMenuName;

    LPCTSTR lpszClassName;

    HICON hIconSm;

} WNDCLASSEX, *PWNDCLASSEX;

窗口是根據窗口類建立的,窗口類相當於一個模板。他定義了各種屬性,定義後打造出來的窗口就是他定義的那個樣子了。如果窗口類沒有定義完全,註冊的時候就會失敗,我在寫的過程中漏寫了幾個屬性導致這樣的錯誤

該消息是在註冊的時候發生的。

Msg數據結構

ttypedef struct tagMSG { HWND hwnd ; UINT message ; WPARAM wParam ; LPARAM lParam ; DWORD time ; POINT pt ; } MSG, * PMSG ;

從消息隊列中取得的消息來填充各個屬性。

Point數據結構

typedef struct tagPOINT { LONG x ; LONG y ; } POINT, * PPOINT

存放該消息時的鼠標座標。

建立窗口

HWND CreateWindow(     

    LPCTSTR lpClassName,

    LPCTSTR lpWindowName,

    DWORD dwStyle,

    int x,

    int y,

    int nWidth,

    int nHeight,

    HWND hWndParent,

    HMENU hMenu,

    HINSTANCE hInstance,

    LPVOID lpParam 

);

其中的大部分參數都可以猜出意思,最後一個參數有必要解釋一下,是用來傳遞額外的數據的,這裏並沒有用到就設爲NULL了。該函數返回一個窗口句柄,用來唯一表示一個窗口的。這樣其他函數才知道作用在哪個窗口上。

建立窗口後調用ShowWindow (hwnd, iCmdShow)來顯示窗口,第二個參數是初始的顯示方式。UpdateWindow (hwnd)是用來重畫窗口的。

消息循環

while(GetMessage (&msg, NULL, 0, 0)) {

   TranslateMessage (&msg) ;

   DispatchMessage (&msg) ; }   

消息循環功能是將事件轉換爲消息並給處理函數處理。TranslateMessage用來解釋消息,DispatchMessage用來投遞給消息處理函數,非常神奇的一個函數。

WM_PAINT消息

顯示區域無效時才產生WM_PAINT消息,遮蓋後重新要求顯示,此時爲無效。當然改變窗口大小也爲無效。

關於程序的結束

當WM_DESTROY消息收到後執行PostQuiteMessage產生WM_QUITE消息,這樣該消息GetMessage()時返回的是0,導致消息循環結束。WinMain函數繼續執行,這個例子中是返回並結束程序。從這裏我可以想象到,windows程序主要是消息循環和消息處理函數的交互。除此之外的都是一些設置和初始化等事務性的例程。

彙編版本

;==========================

;  (c)狗尾草 2008.1.19

;==========================

.386

.Model Flat, StdCall

Option Casemap :None

Include windows.inc

Include user32.inc

Include kernel32.inc

Include gdi32.inc

includelib gdi32.lib

IncludeLib user32.lib

IncludeLib kernel32.lib

include macro.asm

 

 WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

 WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD

 

.DATA

 szClassName db "HELLOWIN",0

 

.DATA?

 hInstance dd ?

 

.CODE

START:

 invoke GetModuleHandle,NULL  ;取得當前進程實例

 mov hInstance,eax

 invoke WinMain,hInstance,NULL,NULL,SW_SHOWDEFAULT

 invoke ExitProcess,0

WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD

 LOCAL wc   :WNDCLASSEX

 LOCAL msg  :MSG

 local hWnd :HWND

 

 mov wc.cbSize,sizeof WNDCLASSEX

 mov wc.style,CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW

 mov wc.lpfnWndProc,offset WndProc

 mov wc.cbClsExtra,NULL

 mov wc.cbWndExtra,NULL

 push hInst  ;存儲器變量用push和pop完成賦值

 pop wc.hInstance

 mov wc.hbrBackground,COLOR_BTNFACE+1

 mov wc.lpszMenuName,NULL

 mov wc.lpszClassName,offset szClassName

 invoke LoadIcon,hInst,100

 mov wc.hIcon,eax

 invoke LoadCursor,NULL,IDC_ARROW

 mov wc.hCursor,eax

 mov wc.hIconSm,0

 invoke RegisterClassEx, ADDR wc

 invoke CreateWindowEx,NULL,ADDR szClassName,CTXT("henry's hellowin program"),WS_OVERLAPPEDWINDOW,200,200,400,200,NULL,NULL,hInst,NULL

 mov hWnd,eax

 invoke ShowWindow,hWnd,SW_SHOWNORMAL

 invoke UpdateWindow,hWnd

 

 StartLoop:

  invoke GetMessage,ADDR msg,NULL,0,0

   cmp eax, 0

   je ExitLoop

    invoke TranslateMessage, ADDR msg

    invoke DispatchMessage, ADDR msg

   jmp StartLoop

 ExitLoop:

 

mov eax,msg.wParam

ret

WinMain endp

WndProc proc hWin:DWORD,uMsg:DWORD,wParam :DWORD,lParam :DWORD

   LOCAL hdc:HDC

   LOCAL ps:PAINTSTRUCT

   LOCAL rect:RECT

 .if uMsg==WM_CREATE

  

 .elseif uMsg == WM_DESTROY

  invoke PostQuitMessage,NULL

 .elseif uMsg == WM_PAINT

  invoke BeginPaint,hWin,ADDR ps

  mov hdc,eax

  invoke GetClientRect,hWin,ADDR rect

  invoke DrawText,hdc,CTXT("HELLO,WINDOWS XP!"),-1,ADDR rect,DT_SINGLELINE or DT_CENTER or DT_VCENTER

  invoke EndPaint,hWin,ADDR ps

 .else

  invoke DefWindowProc,hWin,uMsg,wParam,lParam

 .endif

 ret

WndProc endp

END START

彙編版本基本結構同C版,主要更注重細節方面。程序實例句柄由一個特殊的函數取得GetModuleHandle。函數符合先聲明後使用的特點。這點與嚴格的c語言是相同的。各種高級的僞指令的使用,可以說和C語言已經是哥哥弟弟了。程序運行的結果和C版沒任何區別

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章