转至:http://hi.baidu.com/tiancao222/item/d2f0dc370617dff3e6bb7a61
一、 概念:
1. 什么是窗口
2. 什么是消息
3. 什么是窗口过程函数
4. 怎么创建窗口
5. 消息是怎么传递并处理的
二、 方法:
用调用windows API的方法创建了两个窗口,父窗口和子窗口。父窗口处理了鼠标左键按下和鼠标右键按下的消息,子窗口只处理了左键按下的消息。
验证用的源码:Hello Windows.rar
三、 过程:
1. 在子窗口单击左键,弹出“子窗口左键按下”提示,之后父窗口未出现“父窗口左键按下”的提示。
2. 在父窗口单击右键,弹出“父窗口右键按下”的提示。
3. 在子窗口单击右键,没有任何提示,父窗口也没有任何提示。
四、 结论:
消息是根据窗口进行分发的,而不考虑该窗口的从属关系。也就是说在子窗口中产生的消息只在子窗口函数中处理,处理完后不会再把消息传递给父窗口(除非你自己做反射)。
对窗口、线程、消息的关系总结:
1.每一个窗口都是属于某一个线程的
注意是线程
2.每一个窗口都“绑定”了一个“窗口函数”!~
也就是在每个窗口上产生的消息,会发往对应的函数来处理!~
3.每一个线程都有一个属于自己的“消息队列”
图示:
五、 概念解释:
1. 什么是窗口
MSDN: In a graphical Win32-based application, a window is a rectangular area of the screen where the application displays output and receives input from the user. Therefore, one of the first tasks of a graphical Win32-based application is to create a window.
大意:窗口就是一个矩形区域,应用程序可以用它来显示输出,或者从user来获得输入(键盘鼠标)。
在windows中,“一切皆为窗口”。虽然不是很贴切,但是说明了窗口的普遍性和其重要性。
比如,你现在看到的QQ聊天窗口,就是由多个窗口组成的!~
2. 什么是消息
MSDN: A data packet used for communicating information or a request. Messages can be passed between the operating system and an application, different applications, threads within an application, and windows within an application.
大意:消息就是一组数据包(结构体),用于传递信息。消息可以在操作系统和一个进程之间传递,也可以在两个不同的进程间传递,也可以在同一个进程的不同线程间传递或同一个进程的不同窗口间传递。
比如,你在QQ聊天窗口中点一下鼠标,打字等,都会产生消息。
在代码中消息是以消息结构体MSG来保存的,里面的成员包括处理该消息的窗口句柄,消息代码,消息产生的时间和光标的位置等。
3. 什么是窗口过程函数
我们鼠标、键盘消息是在窗口上产生的,windows会把消息传给该窗口所属线程的消息队列中。然后这个消息在某个时间被这个窗口对应的处理函数来“搞定”。
这个和窗口绑定的“处理消息的函数”就是“窗口过程函数”。
一般的,一个窗口类绑定一个窗口过程函数。
4. 怎么创建窗口
首先,对于windows系统来讲,不管你是C#还是C++还是JAVA,要创建一个标准的窗口,都是调用相同的API的~
只是在VC、C# .NET或用JAVA开发windows时,开发工具都帮你把创建窗口“通用的部分”封装了起来,你是看不到的。
在我们C#的代码中,在Main函数里已经给我们创建好了第一个窗口Fomr1。为我们免去了N多初始化的麻烦,但是我们也就不知道窗口是怎么被创造出来的了。
因此,这里的示例代码使用的是最原始,最明显的方法来创建一个窗口,显示出来并处理你发出的消息。我们用C语言来调用API创建窗口。
创建窗口的4个步骤:
1) 初始化窗口类(实际上是一个结构体)
WNDCLASS wndclass;
2) 注册这个类
RegisterClass(……);
3) 创建窗口
hwnd = CreateWindow(……);
4) 显示
ShowWindow(hwnd, iCmdShow);
精简后的创建窗口程序主干:
WinMain(……)
{
……
HWND hwnd;//用来存放窗口句柄
MSG msg;//用来存放消息的结构体
WNDCLASS wndclass;// 1)窗口结构体
RegisterClass(……);// 2)注册窗口类
hwnd = CreateWindow(……);// 3)创建窗口
ShowWindow(hwnd, iCmdShow);// 4)显示
UpdateWindow(hwnd);//更新
//下面是消息循环
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
说明:
1) WNDCLASS wndclass;
这个结构体里存放了窗口的各种初始数据。如窗体类的风格,窗体上显示的图标,鼠标的图标等。
2) RegisterClass(……);
调用该函数通知系统被注册类的窗口的消息,windows为后面创建窗口准备一系列资源。
3) hwnd = CreateWindow(……);
调用该函数创建较迭的、弹出的或子窗口。它指定窗口类、窗口标题、窗口风格和窗口的初始大小与位置等。
创建出来的窗口以属于“活动”状态,已经开始进行消息处理。只是没有被“显示”出来。
4) ShowWindow(hwnd, iCmdShow);
该函数用来设置指定窗口的“显示状态”,如大小、位置、是否隐藏等。
5. 消息是怎么传递并处理的
消息(Message)在窗口中产生后,系统把它放入到该窗口所属线程的消息队列中,等待处理。
线程将队列中的消息取得后,在翻译后,将它“投放”到相应的窗口过程函数中进行处理。
消息处理机制的核心代码:
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
根据MSDN,上面几个函数的作用:
1.GetMessage只获取自己所属线程的消息队列中的消息,包括windows消息和
通过PostThreadMessage发送的线程消息。
2.TranslateMessage是为了将虚拟键消息“翻译”成字符消息,然后把字符消息放回到线程的消息队列中,在下一次被GetMessage取得。(具体内容见MSDN)
3.DispatchMessage的作用是将从GetMessage获得的消息分发给相应的窗口处理函数(WndProc),然后窗口过程函数对消息进行处理。
上面代码中使用while循环的意义是:循环是应用程序能够持续存在的根本原因。如果循环退出,则应用程序就结束了。