窗口是屏幕上的矩形區(qū)域,消息窗口功能有限,因?yàn)槲覀儾荒芴砑铀膫€(gè)以上的按鈕以及菜單等,而且添加的按鈕必須是windows提供的按鈕,不能自定義。所以我們有必要自己創(chuàng)建一個(gè)多功能可自定義的窗口。

自己的窗口

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

HWND CreateWindow(      

    LPCTSTR lpClassName//窗口類

    LPCTSTR lpWindowName

    DWORD dwStyle

    int x

    int y

    int nWidth

    int nHeight

    HWND hWndParent

    HMENU hMenu

    HINSTANCE hInstance

    LPVOID lpParam 

);

從函數(shù)原型可以看出創(chuàng)建窗口的各種屬性,一種窗口含有顯示程序名稱的標(biāo)題列、菜單甚至可能還有工具列和滾動(dòng)條,另一種窗口是對(duì)話框,在上面可以放置各種控件。而這些控件也是窗口,稱為子窗口。

窗口消息處理程序

窗口處理函數(shù)是理解消息機(jī)制的關(guān)鍵,windows處理將消息循環(huán)中取得的各種消息放入這個(gè)函數(shù)中進(jìn)行處理,該函數(shù)會(huì)比對(duì)各個(gè)匹配項(xiàng)直到找到對(duì)應(yīng)的處理項(xiàng),如果沒有找到就傳給一個(gè)默認(rèn)的窗口函數(shù),是程序正常結(jié)束。該函數(shù)可以在程序中也可以在dll中。使用窗口類使多個(gè)窗口能夠?qū)儆谕粋€(gè)窗口類,并使用同一個(gè)窗口消息處理函數(shù)。

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);

}

調(diào)用的函數(shù)和功能如下,絕大多數(shù)在winuser.h:

LoadIcon

 加載圖標(biāo)供程序使用

LoadCursor

加載鼠標(biāo)光標(biāo)供程序使用

GetStockObject

 取得一個(gè)圖形對(duì)象

RegisterClass

 為程序窗口注冊(cè)窗口類別

MessageBox 

顯示消息框

CreateWindow

 根據(jù)窗口類別建立一個(gè)窗口

ShowWindow

 在屏幕上顯示窗口

UpdateWindow

 指示窗口自我更新

GetMessage

 從消息隊(duì)列中取得消息

TranslateMessage 

轉(zhuǎn)譯某些鍵盤消息

DispatchMessage

 將消息發(fā)送給窗口消息處理程序

PlaySound 

播放一個(gè)聲音文件

BeginPaint

 開始繪制窗口

GetClientRect 

取得窗口顯示區(qū)域的大小

DrawText

 顯示字符串

EndPaint

 結(jié)束繪制窗口

PostQuitMessage

 在消息隊(duì)列中插入一個(gè)「退出程序」消息

DefWindowProc

 執(zhí)行內(nèi)定的消息處理

關(guān)于一些常量定義的約定如下:

前綴

類別

CS

窗口類別樣式

CW

建立窗口

DT

繪制文字

IDI

圖示ID

IDC

游標(biāo)ID

MB

消息框

SND

聲音

WM

窗口消息

WS

窗口樣式

常數(shù)值是沒有必要記憶的,記住常量的一些大寫標(biāo)識(shí)符就可以了。

各種句柄

標(biāo)識(shí)符

含義

HINSTANCE

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

HWND

窗口句柄

HDC

設(shè)備內(nèi)容句柄

句柄通常是調(diào)用函數(shù)取得的,起到一個(gè)標(biāo)識(shí)身份的目的。其實(shí)實(shí)質(zhì)是一個(gè)32位整數(shù)。

數(shù)據(jù)結(jié)構(gòu)注解

窗口類結(jié)構(gòu)

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;

窗口是根據(jù)窗口類建立的,窗口類相當(dāng)于一個(gè)模板。他定義了各種屬性,定義后打造出來的窗口就是他定義的那個(gè)樣子了。如果窗口類沒有定義完全,注冊(cè)的時(shí)候就會(huì)失敗,我在寫的過程中漏寫了幾個(gè)屬性導(dǎo)致這樣的錯(cuò)誤

該消息是在注冊(cè)的時(shí)候發(fā)生的。

Msg數(shù)據(jù)結(jié)構(gòu)

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

從消息隊(duì)列中取得的消息來填充各個(gè)屬性。

Point數(shù)據(jù)結(jié)構(gòu)

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

存放該消息時(shí)的鼠標(biāo)坐標(biāo)。

建立窗口

HWND CreateWindow(      

    LPCTSTR lpClassName

    LPCTSTR lpWindowName

    DWORD dwStyle

    int x

    int y

    int nWidth

    int nHeight

    HWND hWndParent

    HMENU hMenu

    HINSTANCE hInstance

    LPVOID lpParam 

);

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

建立窗口后調(diào)用ShowWindow (hwnd, iCmdShow)來顯示窗口,第二個(gè)參數(shù)是初始的顯示方式。UpdateWindow (hwnd)是用來重畫窗口的。

消息循環(huán)

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

   TranslateMessage (&msg) ; 

   DispatchMessage (&msg) ; }    

消息循環(huán)功能是將事件轉(zhuǎn)換為消息并給處理函數(shù)處理。TranslateMessage用來解釋消息,DispatchMessage用來投遞給消息處理函數(shù),非常神奇的一個(gè)函數(shù)。

WM_PAINT消息

顯示區(qū)域無效時(shí)才產(chǎn)生WM_PAINT消息,遮蓋后重新要求顯示,此時(shí)為無效。當(dāng)然改變窗口大小也為無效。

關(guān)于程序的結(jié)束

當(dāng)WM_DESTROY消息收到后執(zhí)行PostQuiteMessage產(chǎn)生WM_QUITE消息,這樣該消息GetMessage()時(shí)返回的是0,導(dǎo)致消息循環(huán)結(jié)束。WinMain函數(shù)繼續(xù)執(zhí)行,這個(gè)例子中是返回并結(jié)束程序。從這里我可以想象到,windows程序主要是消息循環(huán)和消息處理函數(shù)的交互。除此之外的都是一些設(shè)置和初始化等事務(wù)性的例程。

匯編版本

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

;  (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  ;取得當(dāng)前進(jìn)程實(shí)例

 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  ;存儲(chǔ)器變量用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

匯編版本基本結(jié)構(gòu)同C版,主要更注重細(xì)節(jié)方面。程序?qū)嵗浔梢粋€(gè)特殊的函數(shù)取得GetModuleHandle。函數(shù)符合先聲明后使用的特點(diǎn)。這點(diǎn)與嚴(yán)格的c語言是相同的。各種高級(jí)的偽指令的使用,可以說和C語言已經(jīng)是哥哥弟弟了。程序運(yùn)行的結(jié)果和C版沒任何區(qū)別。