三、窗口与消息

本文深入讲解Windows编程的基础,包括窗口创建、消息处理流程、关键函数的使用及消息类型的解析。通过对示例代码的分析,帮助读者理解如何创建窗口类、处理窗口消息以及实现基本的绘图操作。
首先上代码,下面讨论都根据此展开.
#include "stdafx.h"
#include <Windows.h>
#include<mmsystem.h>    //窗口创建时播放声音所要包含的头文件
#pragma comment(lib,"winmm.lib")
LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
int WINAPI WinMain(  HINSTANCE hInstance,  HINSTANCE hPrevInstance,   LPSTR lpCmdLine, int nCmdShow)
{
	TCHAR appszName[]=TEXT("demo");
	WNDCLASS wndcls;
	wndcls.lpszClassName=appszName;
	wndcls.cbClsExtra=NULL;
	wndcls.cbWndExtra=NULL;
	wndcls.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wndcls.hCursor=LoadCursor(hInstance,IDC_ARROW);
	wndcls.hIcon=LoadIcon(hInstance,IDI_APPLICATION);
	wndcls.hInstance=hInstance;
	wndcls.lpfnWndProc=WindowProc;
	wndcls.lpszMenuName=NULL;
	wndcls.style=CS_HREDRAW|CS_VREDRAW;
	if(!RegisterClass(&wndcls))
	{
		MessageBox(NULL,_T("注册失败"),TEXT("提示"),NULL);
	}
	HWND hwnd=CreateWindow(appszName,_T("demo"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		NULL,NULL,hInstance,NULL);
	ShowWindow(hwnd,nCmdShow);  //nCmdShow确定最初的显示方式
	UpdateWindow(hwnd);
	MSG msg;
	while(GetMessage(&msg,NULL,NULL,NULL))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
LRESULT CALLBACK WindowProc(  HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	RECT rect;
	GetClientRect(hwnd,&rect);
	HDC hdc;
	PAINTSTRUCT ps;
	switch (uMsg)
	{
	case WM_CREATE:
		PlaySound(_T("hellowin.wav"),NULL,SND_FILENAME|SND_ASYNC);
		return 0;

	case WM_PAINT:
		hdc=BeginPaint(hwnd,&ps);
		DrawText(hdc,_T("demo"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
		EndPaint(hwnd,&ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

3.1窗口创建
窗口是在“窗口类”的基础上建立的,“窗口类”标识了窗口的消息处理函数。(这里我们都已经知道多个窗口对象属于同一个窗口类,并使用同一个窗口消息处理函数)。
就如面向对象程序设计,我们这里可以认为窗口是一种对象,函数则是窗口消息过程。数据则是窗口过程保存的信息和windows为每个窗口和窗口类别保存的信息。Windows通过调用窗口过程处理给窗口发送的消息,窗口过程处理完成后将控制再传给Windows。
上述代码中用到的绝大部分函数都声明于WINUSER.H中。如LoadIcon,CreateWindow等。
大写字母标志符定义的规则:

新的数据类型
UINT    unsigned int(无正负号整数)
PSTR   指向字符串指针 即char*
WPARAM  LPARAM   这两个参数前面的L和W来源于16位Window时期,那时WndProc的第三个参数定义为WORD(16位无正负号短整数),第四个参数定义为LONG(32位有正负号长整型)。 在32位系统中WPARAM定义为UINT,LPARAM定义为LONG,都是32位值,但仍保留了16位系统中的定义方法。
LRESULT  定义为LONG
WINAPI  CALLBACK    这是窗口过程和WinMain函数定义的形态,这两个标识符都被定义为_stdcall. 关于stdcall,我们只要知道它是函数调用约定的一种、__stdcall表示
1.参数从右向左压入堆栈
2.函数被调用者修改堆栈
3.函数名(在编译器这个层次)自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸
在win32应用程序里,宏APIENTRY,WINAPI,都表示_stdcall,非常常见。

MSG                 消息结构
WNDCLASS       窗口类别结构
PAINSTRUCT     绘图结构
RECT                 矩形结构
HINSTANE        执行实例句柄
HWND              窗口句柄
HDC                 设备内容句柄
	windows中许多变量都采用“匈牙利表示法”命名规则,即:变量名以一个或多个小写字母开始。这些字母表示变量的数据型态。如, szCmdLine  sz代表「以0结尾的字符串」	hInstance hPrevInstance h表示「句柄」;在iCmdShow   i前缀表示「整数」。各种通用前缀如下表所示:
上面代码中窗口类的各参数分开定义,通过这种方式定义是非常方便的,虽然每个窗口都以同样的方式工作,但并非所有窗口都一样。他们有不同大小,位置等,这样我们就可以通过不同的特征值定义出来。   消息循环、
typedef struct tagMS
{
HWND hwnd ;
UINT message ;
WPARAM wParam
LPARAM lParam
DWORD time ;
POINT pt ;
}
MSG, * PMSG ;

hwnd 接收消息的窗口句柄。
message 消息标识符。这是一个数值,每个消息均有一个对应的标识符,这些标识符定义于Windows  头文件(大多在WINUSER.H中),以前缀WM开头。
wParam   一个32位的其含义和数值根据消息的不同而不同。
lParam     一个32位的消息参数,其值与消息有关。
time      消息放入消息队列中的时间。
pt        消息放入消息队列时的鼠标坐标。

	在消息循环中,只要从消息队列中取出消息的message字段不为WM_QUIT(其值为0x0012), GetMessage就传回一个非零值。 WM_QUIT消息将导致GetMessage传回0。
 
窗口过程定义的形式为
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
一个窗口过程总是与RegisterClass注册的特定窗口类别相关联。通过上面我们可以注意到前四个参数是与消息结构中相同。
程序一般不调用窗口过程,而一般由windows调用。但通过SendMessage函数,程序能直接调用自己的窗口过程。
 
消息处理,上述我们处理了三个消息:
WM_CREATE
  窗口过程接收处理的第一个消息。当WinMain中处理CreateWindow时接收。调用WndProc时,第一个参数设定为窗口句柄,第二个参数设定为WM_CREATE。 WndProc处理WM_CREATE消息并将控制传回给Windows。然后WinMain中进行下一步的处理。
通常,窗口过程在WM_CREATE处理期间进行一次窗口初始化。本例中播放声音。最后, WndProc通过从窗口消息处理程序中传回0,结束了整个WM_CREATE的处理。
 
WM_SIZE (何时发送和应用点)
	1.当WinMain函数调用CreateWindow时,窗口过程收到WM_CREATE消息,而第一条WM_SIZE消息就发生在那之后(准确的说是WinMain调用ShowWindow函数时)【应用汇总:①可以在窗口过程的WM_SIZE处理中获取字体的高度和宽度;     ②可以获取窗口(客户区)的宽度和高度(59页和81页有WM_SIZE相应lParam变量的解释);     ③可以对滚动条进行诸如SetScrollInfo的初始化工作】。

	2.窗口尺寸改变时. 【应用汇总:①在WndProc处理WM_SIZE消息的时候设定滚动条的范围相对于在WM_CREATE中更合适(客户区大小改变后,滚动条页需要做出相应调整),例如SetScrollInfo的使用;      ②缩放编辑控件的动作也应该放在此处,除以上原因以外,还因为此动作需要获取客户区大小

WM_PAINT
我们都知道,当显示区域无效需要更新画面时就发送个消息。那什么情况下才会发送呢?
1、窗口建立时,这时候肯定整个显示区域是无效的。发送第一条WM_PAINT消息(通常发生于UpdateWindow)
2、改变窗口大小时。如风格CS_HREDRAW等,在窗口大小变化后整个显示内容无效,这时候也就需要重绘了。
3、最小化窗口恢复时。因为窗口显示区域涉及的数据量很大,所以一般windows不会保存显示区域的内容。这时窗口过程收到此消息,自动恢复窗口内容。
4、移动窗口导致多个窗口重叠时。window不会保存窗口中其他窗口遮盖的内容。当被遮盖内容重新露面时就被标志为无效,同样发送此消息重绘。

WM_PAINT的处理总是从一个BeginPaint开始:
hdc=BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);

调用BeginPaint,如果显示区域背景还未被删除,则由Windows来删除。如果消息处理程序不处理WM_PAINT(很少见),必须传送给DefWindowProc,DefWindowProc也只是依次调用BeginPaint和EndPaint使显示区域有效。
 
WM_DESTROY
该消息指示Windows正在根据使用者指示关闭窗口。该程序通过调用PostQuitMessage以标准方式响应WM_DESTROY消息:
PostQuitMessage(0);
该函数在程序的消息队列中插入一个WM_QUIT消息。前面提到过, GetMessage对于除了WM_QUIT之外的从消息队列中取出的所有消息都传回非0值。而当GetMessage得到一个WM_QUIT消息时,它传回0。这将导致WinMain退出消息循环,并终止程序。然后程序执行下面的叙述:
return msg.wParam ;
结构的wParam字段是传递给PostQuitMessage函数的值(通常是0)。然后return叙述将退出WinMain并终止程序。
 
Windows程序设计难点
从上面我们可以得知,基本一个程序的所有动作都在窗口消息处理函数中发生。而windows做的一切,也只是响应发送给窗口消息处理函数的消息而已。这是我们在写程序之前必须要明白的一件事情。
所有WndProc调用都以消息的形式进行。大多数Windows程序的主要部分都用来处理消息。 Windows可以发送给窗口消息处理程序的消息通常都以WM开头,并且都在WINUSER.H头文件中定义。
一个窗口消息处理函数可以处理同一个类别建立的多个窗口消息。hwnd标志具体哪个窗口。参数message是WM_SIZE。消息WM_SIZE的参数wParam的值是SIZE_RESTORED、 SIZE_MINIMIZED、 SIZE_MAXIMIZED、 SIZE_MAXSHOW或SIZE_MAXHIDE (在WINUSER.H表头文件中分别定义为数字0到4)。即参数wParam表明窗口是非最小化还是非最大化,是最小化、最大化,还是隐藏。
lParam参数包含了新窗口的大小,新宽度和新高度均为16位值,合在一起成为32位的lParam。
 
队列化与非非队列化消息
队列化消息是由Windows放入程序消息队列中的。
非队列化的消息在Windows调用窗口时直接送给窗口过程。
也就是说队列化消息直接发送给消息队列,而非发送给窗口消息处理函数。
                                                                                                                                          
队列化消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP消息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出。队列化消息还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。

	非队列化消息则是其它消息。在许多情况下,非队列化消息来自呼叫特定的Windows函数。例如,当WinMain呼叫CreateWindow时, Windows将建立窗口并在处理中给窗口消息处理程序发送一个WM_CREATE消息。当WinMain呼叫ShowWindow时, Windows将给窗口消息处理程序发送WM_SIZE和WM_SHOWWINDOW消息。当WinMain呼叫UpdateWindow时, Windows将给窗口消息处理程序发送WM_PAINT消息。键盘或鼠标输入时发出的队列化消息信号,也能在非队列化消息中出现。例如,用键盘或鼠标选择了一个菜单项时,键盘或鼠标消息就是队列化的,而说明菜单项已选中的WM_COMMAND 消息则可能就是非队列化的。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值