Window消息机制



Window消息机制。

简介:

在Windows中消息是其通信方式中的最重要的一种。传统的程序从你的main()函数开始执行,然后一行行的执行你的代码,最终推出程序。这跟Windows中的执行方式是不一样的。在Windows中的方式是你的程序来响应事件。而这些事件是由消息唤起的。

 

消息可以唤起很多事件,这些消息可以是由用户激发的,也可以是操作系统,或者是其他的应用程序。一个事件可以是由鼠标的应答,按键的按下,或者是你的窗口的大小的改变。这里有两种消息,一种是Window 消息,一种是线程消息。不过线程消息还出在争议中,所以我更愿意讲Window消息。

 

Window消息:

总的来说,一个消息总是能够被送给一个窗口的。所有的消息都能送到你的,并存储在消息队列中,消息队列是内存中的一块区域,用来存储程序之间的消息交换。

消息循环:

通过消息循环可以从消息队列中检索消息。一旦消息被接受后,消息循环就会把通过消息处理把消息进行分发,有一个函数设计成帮助消息循环来处理消息。

消息循环当接受到消息WM_QUIT的时候选择退出,同时通告应用程序结束。这个消息会在用户选择了文件菜单中的推出键,或者是点击了关闭按钮(在你窗口的右上角的一个小X的button),或者是按下了Alt+F4.windinws有默认的消息处理可以来处理绝大部分的消息,只要你的窗口是Window默认行为。事实上,所有的标准控件都是一个有着简单的消息处理的窗口。用button为例,当得到WM_PAINT消息的的时候,它选择了重绘button。当你左键点击了button的时候,它会得到一个WM_LBUTTONDOWN消息,然后绘制一个按下的button。当你把鼠标松开的时候,它会接收到一个WM_LBUTTONUP的消息,然后绘制button。

Windows 定义了很多不同种消息类型(都是被存储为UINT)。他们通常以字面组合WM_开头,比如说WM_CHAR和WM_SIZE.一般来说通过消息的名字就可以很容易的知道消息指示的是什么意思。WM_SIZE来指示窗口大小的消息,WM_CHAR来只是字符被键入的消息,等等。在MFC中有一个关于消息处理函数名字转换的标准,通常去掉WM_然后替换为“On”。比如说消息WM_SIZE被OnSize处理。

一个消息带有两个参数的话,那么就会给你即将要响应的事件更多的信息。每一个参数都是一个32bit的值,lParam和wParam。例如,WM_MOUSEMOVE,在一个参数中给你鼠标的位置信息,在另一个参数中来指示Alt,Shift,CTRL和鼠标按键的标志位。

一个消息可以返回一个值,允许你发送反馈消息给发送消息的程序。比如WM_QUERYENDSESSION消息被Windows发出,在电脑关闭之前。期望你返回一个布尔值。如果你的应用程序可以方便的中止,它将返回TRUE,否则,它将要返回一个FALSE,而消息例如WM_CTLCOLOR消息期望你返回一个HBRUSH。

注意:在后面的教程中,我会只是简单的关注MFC。所以的内容都可以应用到SDK程序或者是MFC程序中。

 

消息处理:

很幸运,MFC给了消息循环所需要的所有代码。在CWinApp的成员函数Run 被WinMain调用的,提供了消息循环来处理发送给窗口的消息。你需要做得唯一事情就是收到消息后创建消息处理,然后通知MFC。但是,如何创建消息处理呢?一旦你有MFC 的c++的窗口封装类,那么你可以很容易的通过ClassWizard来创建消息处理。

 

使用ClassWizard来创建消息处理:

按下Ctrl+W 启动ClassWizard,或者右键点击选择ClassWizard从上下文菜单中选择添加按钮。打开ClassWizard后选择消息映射标签。在Class name栏选择你的C++的类名。在目标IDS中选择菜单项的ID,控件的ID,或者好似第一选项来处理消息。悬着消息从消息列表中,例如WM_SIZE,你点击了加入函数,点击Ok,然后点击编辑代码。ClassWizard将会写出一个有着合适的函数原型的空函数,代码会生成如下:

 

void CAboutWindow::OnSize(UINT nType, int cx, int cy)

{

CDialog::OnSize(nType, cx, cy);

// TODO: Add your message handler code here

 

 

// Here is where you can resize controls in your window, change

 

// the size of a bitmap in it, or do what ever you can think of.

 

}

现在,你就可以处理消息了。如果你想处理一个消息,然后让缺省的消息处理来处理其它的消息,那么你应该调用基类的成员函数来响应这些消息。用下面的消息WM_CLOSE消息处理为例子。

 

void CAboutWindow::OnClose()

{

//The User or another program is trying to close our window…

 

//If you don’t add code to close the window, your window will never close

 

}

如果你想Windows处理一个消息,你可以调用基类的成员函数OnCloase:

 

void CAboutWindow::OnClose()


{

MessageBox(_T(“Closing the window!”))

//Call the Base class member function, which will close the window.

 

CWnd::OnClose()

}

如果你只是哟昂处理部分事件,例如,一个程序提示用户是否确定他要关闭窗口。

 

void CAboutWindow::OnClose()

{

int Ret = MessageBox(_T(“Are you sure you want to close the window?”),

_T(“Close Window?”), MB_YESNO);

if(Ret == IDYES){

// The User is sure, close the window by calling the base class

 

// member

 

CWnd::OnClose()

}

else{

// The user pressed no, screen out the message by not calling

 

// the base class member

 

 

//Do nothing

 

}

}

发送消息:

除了接受消息外,你也会经常发现你自己也需要发送消息。你可以通过发送消息来进行程序间的通信,或者和其他的程序进行通信。为了你能够发送消息,你需要一个指针指向一个C++窗口类。这可以被用来被不同函数检索,包括CWnd::FindWindow,GetDlgItem(),GetParent()等等。CWnd类有一个成员函数SendMessage()允许你发送消息给它的窗口。例如,你有一个CWnd的指针指向了一个计算器,如果你想关闭掉它。你可以发送WM_CLOSE消息,这个消息会通告计算器他将要被关闭。你可以用下面的代码。为了得到指向计算器的一个指针,我用了静态的CWnd::FindWindow()函数来查找窗口标题,来确定那个是“Calculatror”

 

CWnd *pCalc;

//Get a pointer to the “Calculator” Window

 

pCalc = CWnd::FindWindow(NULL, _T(“Calculator));

if(pCalc == NULL){

//Couldn’t find Calculator

}

else{

pCalc->SendMessage(WM_CLOSE);

//Presto! The Calculator should close.

}