揭开.NET消息循环的神秘面纱(一)(转)

本文转自:http://www.cnblogs.com/sakiwer/archive/2009/12/15/1619282.html

 

-----------------------------------------------------------------------------------------------------------------------------------------------------

 

曾经在Win32平台下奋战的程序员们想必记得,为了弄清楚“消息循环”的概念,度过多少不眠之夜。尽管如今在应用程序代码的编写过程中,我们已经不再需要它,但是深刻理解Windows平台内部的消息流转机制依然必要..

在早年直接用Win32/Win16 API写程序的时代,消息循环是我们必须搞懂的第一个观念。现在,不管你用是Windows上面的哪一套Application Framework(MFC、VCL、VB、.NET Framework),甚至Unix、Linux、MacOSX上面的Application Framework,都不太容易看到消息循环。事实上,消息循环依然存在,只是被这些ApplicationFramework包装起来,深深地埋藏在某 个角落。

本文章试图唤起大家对于消息循环的回忆,也试图解释消息循环如何被封装进.NET Framework的Windows Forms中。虽然Windows Forms将这一切都藏起来,但是也留下许多空间,让我们可以自行处理Win32的消息。

传统的Windows 程序

传统的Windows程序,只利用Win32 API撰写,下面是一个程序范例,为了节省篇幅,我将其中许多程序代码省略:

// 程序进入点

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow){ 
MSG msg; 
if (!InitInstance (hInstance, nCmdShow)){ 
return FALSE;
}

// 主消息循环:

while (GetMessage(&msg, NULL, 0, 0)){ 
TranslateMessage(&msg); DispatchMessage(&msg); 

return (int) msg.wParam; 


// 函数: WndProc(HWND, unsigned, WORD, LONG)
// 用途: 处理主窗口的消息。

LRESULT CALLBACK WndProc(
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 
int wmId, wmEvent; PAINTSTRUCT ps; 
HDC hdc; 
switch (message){ 
case WM_COMMAND: 
wmId = LOWORD(wParam); 
wmEvent = HIWORD(wParam); 
// 剖析菜单选取项目:
switch (wmId){ 
case IDM_ABOUT: 
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX,hWnd, (DLGPROC)About); 
break; 
case IDM_EXIT: 
DestroyWindow(hWnd); 
break; 
default: 
return DefWindowProc(hWnd, message,wParam,lParam); 

break; 
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);

// TODO: 在此加入任何绘图程序代码...
EndPaint(hWnd, &ps); 
break; 

case WM_DESTROY:
PostQuitMessage(0);
break;
default: 
return DefWindowProc(hWnd, message,wParam, lParam); 

return 0; 


// [关于] 方块的消息处理例程。

LRESULT CALLBACK About(HWND hDlg, UINT message,

WPARAM wParam, LPARAM lParam){
switch (message){
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL){
EndDialog(hDlg, LOWORD(wParam)); 
return TRUE; 

break; 

return FALSE; 
}

1、从_tWinMain内,程序进入主消息循环;

2、消息循环从消息队列(Message Queue)中取得一个消息(透过调用GetMessage())。每个执行中的程序都有一个属于自己的消息队列;

3、消息循环根据消息内容来决定消息应该送给哪个Windows Procedure(WndProc),.. 这就称为消息分发(Message Dispatch)。通常“每一种”窗口或控件(control)都有一个Windows Procedure,来处理该种窗口/控件的行为;

4、Windows Procedure根据消息内容来决定应该调用哪个函数(利用Switch/Case语法);.. 

5、Windows Procedure处理完,控制权回到消息循环。继续进行2、3、4、5的动作;

6、当消息队列为空的时候,GetMessage()无法取得任何消息,就会进入Idle(空闲)状态,进入睡眠状态(而不是Busy Waiting)。当消息队列不再为空的时候,程序会自动醒过来,继续进行2、3、4、5的动作;

7、当取得的消息是WM_QUIT,GetMessage()就会得到0的返回值,因而离开消息循环,程序结束。程序会利用调用PostQuitMessage()来将WM_QUIT放置进消息队列中,来造成稍后结束,而不会直接贸然跳离开循环来结束。

虽名为队列(queue),.. 但是消息队列中的消息并非总是先进先出(First In First Out,FIFO),有一些特例:

. 只要消息队列中有WM_QUIT ,就会先取出WM_QUIT,导致程序结束。

. 只有在没有其它消息的时候,WM_PAINT 和WM_TIMER才会被取出。且多个WM_PAINT可能会被合并成一个,WM_TIMER也是如此。

. 利用TranslateMessage()来处理消息,可能会造成新消息的产生。例如:TranslateMessage()可以辨识出WM_KEYDOWN(按键按下)加上WM_KEYUP(按键放开)就产生WM_CHAR(字符输入)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值