Welcome

首页 / 软件开发 / .NET编程技术 / 细说UI线程和Windows消息队列

细说UI线程和Windows消息队列2011-01-12 博客园 金旭亮在Windows应用程序中,窗体是由一种称为“UI线程(User Interface Thread)”的特殊类型的线程创建的。

首先,UI线程是一种“线程”,所以它具有一个线程应该具有的所有特征,比如有一个线程函数和一个线程ID。

其次,“UI线程”又是“特殊”的,这是因为UI线程的线程函数中会创建一种特殊的对象——窗体,同时,还一并负责创建窗体上的各种控件。

窗体和控件大家都很熟悉了,这些对象具有接收用户操作的功能,它们是用户使用整个应用程序的媒介,没有这样一个媒介,用户就无法控制整个应用程序的运行和停止,往往也无法直接看到程序的运行过程和最终结果。

那么,窗体和控件又是如何作到对用户操作进行响应的呢?这一响应是不是由窗体和控件自己“主动”完成的?

换句话说:

窗体和控件具不具备独立地响应用户操作(比如键盘和鼠标操作)的功能?

答案是否定的。

那就奇怪了,比如我们用鼠标点击了一个按钮,并且看到它“陷”下去了,然后又还原,之后,我们确实看到了程序执行了此按钮所对应的任务。难道不是按钮来响应用户操作的吗?

这实际上是一个错觉。这个错觉产生的根源在于不了解Windows内部的运作机理。

简单地说,窗体和控件之所以能响应用户操作,关键在于负责创建它们的UI线程拥有一个“消息循环(Message Loop)”。这个消息循环由线程函数负责启动,通常具有以下的“模样”(以C++代码表示):

MSG msg; //代表一条消息
BOOL bRet;
//从UI线程消息队列中取出一条消息
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
//错误处理代码,通常是直接退出程序
}
else
{
TranslateMessage(&msg); //转换消息格式
DispatchMessage(&msg); //分发消息给相应的窗体
}
}

可以看到,所谓消息循环,其实就是一个While循环语句罢了。

其中,GetMessage()函数每次从消息队列中取出一条消息,此消息的内容被填充到变量msg中。

TranslateMessage()函数主要用于将WM_KEYDOWN和WM_KEYUP消息转换WM_CHAR消息。