首页 > 代码库 > LRESULT CALLBACK WndProc 窗口程序的 重点
LRESULT CALLBACK WndProc 窗口程序的 重点
LRESULT CALLBACK WndProc
Windows程序所作的一切,都是回应发送给窗口消息处理程序的消息。这是概念上的主要难点之一,在开始写作Windows程序之前,必须先搞清楚。
窗口消息处理程序与窗口类别相关,窗口类别是程序调用RegisterClass注册的。依据该类别建立的窗口使用这个窗口消息处理程序来处理窗口的所有消息。Windows通过调用窗口消息处理程序对窗口发送消息。
在第一次建立窗口时,Windows调用WndProc。在窗口关闭时,Windows也调用WndProc。窗口改变大小、移动或者变成图标时,从菜单中选择某一项目、挪动滚动条、按下鼠标按钮或者从键盘输入字符时,以及窗口客户区必须被更新时,Windows都要调用WndProc。
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
所有这些WndProc调用都以消息的形式进行。在大多数Windows程序中,程序的主要部分都用来处理消息。Windows可以发送给窗口消息处理程序的消息通常都以WM开头的名字标识,并且都在WINUSER.H头文件中定义。
窗口中发生的一切都以消息的形式传给窗口消息处理程序。然后,窗口消息处理程序以某种方式回应这个消息,或者将消息传给DefWindowProc,进行默认处理。
让我们来看一个例子。一旦窗口的客户区大小发生了改变,Windows就调用窗口的窗口消息处理程序。窗口消息处理程序的hwnd参数是改变大小的窗口的句柄(请记住,一个窗口消息处理程序能处理依据同一个窗口类别建立的多个窗口的消息。参数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。WINDEF.H中提供了帮助程序写作者从lParam中取出这两个值的宏.
原文:http://c.chinaitlab.com/vc/808874.html
//----------------------------另外的消息相关的知识------------
WIN32的消息流程是很简单的,一个while,一个switch。。
MFC的消息处理流程,事实上和WIN32的一样,不过MFC做了一下封装。
具体的封装很简单,但是难点,也是它用到的一个关键的技术,就是Thunk,Thunk是MFC之所以能够把消息处理放到窗口类的私有函数进行处理的关键技术。
MFC的消息处理内幕基本上是这样:
★要有一个能够进行消息处理的说明宏。DECLARE_MESSAGE_MAP(),这个宏事实上类似定义了一个数组。用来存储你的消息映射。
★要有消息映射,ON_COMMAND、ON_MESSAGE等。这个宏就是往上面的数组中添加映射数据。
★在消息处理内部:
for( int i; i < 数组大小; i++)
 if( msg == 数组[i].msg )
 call 数组[i].Proc;
至于为什么MFC能把消息处理放到类的成员函数中,关键的Thunk技术:
Thunk事实上是一个结构,他被创建在堆中,堆的属性是,可读、可写、可执行,第三条可执行是关键。MFC创建一个thunk,这个thunk里面存储的事实上是一段代码,这段代码可以把Windows消息处理函数的第一个参数,就是hWnd,替换成类的this指针,然后进行一个jmp,用这个this指针去调用类的成员函数,同时thunk被转换为WINPROC类型,因此消息过程事实上先去执行thunk代码,然后再去执行静态的WINPROC,但此时第一个参数已经是this指针了,然后就可以去调用类的成员函数。支持虚拟,继承等。。“我”的空间里有详细的Thunk技术讨论。 http://hi.baidu.com/sdhexu/blog/category/thunk%BC%BC%CA%F5%D1%D0%BE%BF
//--------------------------邪恶的分割线【窗口过程】----------------------------------------------
首先,你必须已经建立了一个窗口。这时,你在这个窗口内点了一下鼠标左键,Windows系统会将这个“消息(或者说事件)”放入到系统消息队列里。之后它会自动分辨出这是哪个窗口所接收的消息,并将这个消息放入到该窗口所对应的应用程序消息队列里。
第二,你的应用程序主函数:WinMain()执行到消息循环后,代码是:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GetMessage()函数从应用程序消息队列里边接收“单击鼠标左键”这一消息,返回值不为0,所以进入循环体,第二个函数用来转换某些键盘消息,而我们点的是鼠标,所以在此直接跳过;第三个函数,将该消息发送回Windows。
Windows接收到DispatchMessage()函数发送的消息后,它会自动找到应把消息发往的窗口过程。并把消息向其传递。之后,进入WndProc函数。你会感到这是“Windows调用了WndProc()”,所以WndProc()才被称为“回调函数”。
进入WndProc()之后,通过switch()逻辑检测接收的信息并做出相应的处理和操作。例如,单击鼠标左键,由WndProc()函数掌管的窗口应该进行怎样的变化……这些东西要我们自己来写喽。但其中有些东西几乎是固定的。比如收到WM_DESTROY消息后,一般调用PostQuitMessage(0)发送WM_QUIT消息,用来结束消息循环,但也不一定,前不久我才写过一个双窗口的程序,当关掉一个窗口后,你应当保证另一个窗口不被关闭……
当WndProc()处理完毕后,DispatchMessage()函数才返回,这时,又要从GetMessage()函数开始新一轮的循环啦~