windows消息汇总.doc_第1页
windows消息汇总.doc_第2页
windows消息汇总.doc_第3页
windows消息汇总.doc_第4页
windows消息汇总.doc_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本文主要包括以下内容: 1、简单理解Windows的消息 2、一段简单的Win32消息循环程序 3、进一步深入理解Windows消息4、队列消息和非队列消息5、WM_COMMAND和WM_NOTIFY1、简单理解Windows的消息 消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了。举个例子来说,鼠标单击某应用程序的一个按钮。这时,Windows(操作系统)给应用程序发送这个消息,通知应用程序该按钮被点击,应用程序将进行相应反应。消息一般用一个32位的数来标识,这个数唯一地标识这个消息。这些消息的标识符一般在头文件winuser.h 中定义,如: #define WM_PAINT 0000F#define WM_QUIT 00012 其实消息本身是一个MSG结构。MSG结构定义如下: typedef struct tagMSG HWND hwnd; /接受消息的窗口句柄UINT message; /消息标识符WPARAM wParam; /32位附加信息 LPARAM lParam; /32位附加信息DWORD time; /消息创建的时间POINT pt; /消息创建时鼠标在屏幕坐标系中的位置 MSG; 也就是说,对于任何一个消息,都有一个MSG变量与之对应,该变量包含了消息的相关信息。而我们在一般情况下,只使用消息的消息标识符,该标识符也唯一地代表了这个消息。举个例子来说,当我们收到一个字符消息的时候,message成员变量的值就是WM_CHAR,但用户到底输入的是什么字符,那么就由wParam和lParam来说明。wParam、lParam表示的信息随消息的不同而不同。Windows操作系统已经给我们定义了大量的消息,这些消息我们称为系统消息。除了系统消息,我们还可以自己定义消息,即自定义消息。值小于00400的消息都是系统消息,自定义消息一般都大于00400。00400WM_USER 0040007FFF自定义消息 在WINUSER.H中,我们有定义: #define WM_USER 00400 对于自定义消息,我们一般采用WM_USER 加一个整数值的方法定义自定义消息,如: #define WM_RECVDATA WM_USER + 1 对于WPARAM和LPARAM附带的信息看下表: Use of the wParam and lParam parameters are summarized here. Message SourcewParam (high word)wParam (low word)lParamMenu0Menu identifier (IDM_*)0Accelerator1Accelerator identifier (IDM_*)0ControlControl-defined notification codeControl identifierHandle to the control window2、通过一段简单的Win32消息循环程序理解Windows消息 ShowWindow(hwnd,iCmdShow);/显示窗口 UpdateWindow(hwnd);/立即显示窗口 /消息循环 MSG msg; while(GetMessage(&msg,NULL,0,0)/从消息队列中取消息 TranslateMessage (&msg); /转换消息 DispatchMessage (&msg); /派发消息 return msg.wParam;/消息处理程序LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)int wmId, wmEvent;switch (message)case WM_COMMAND:wmId = LOWORD(wParam);wmEvent = HIWORD(wParam); if(!wmEvent) /菜单消息 switch (wmId)case IDM_ABOUT:DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam); case WM_LBUTTONUP:InvalidateRect (hWnd, NULL, FALSE) ;return 0 ;case WM_PAINT:hdc = BeginPaint (hWnd, &ps) ;EndPaint (hWnd, &ps) ;break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);return 0;第一段代码涉及GetMessage,TranslateMessage,DispatchMessage这三个函数,相关函数还有PeekMessage,WaitMessage。在此,我们先对这五个函数简单讲解。1)、GetMessage 函数原型: BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); 参数: lpMsg:一个指向MSG结构的指针,该结构用于存放从消息队列里取出的消息。hWnd:窗口句柄。如果该参数是非零值,则GetMessage只检索该窗口(也包括其子窗口)消息,如果为零,则GetMessage检索整个进程内的消息。wMsgFilterMin:指定被检索的最小消息值,也就是消息范围的下界限参数。wMsgFilterMax:上界限参数。如果wMsgFilterMin和wMsgFilterMax都为零,则不进行消息过滤,GetMessage检索所有有效的消息。 返回值 GetMessage检索到WM_QUIT消息,返回值是零;其它情况,返回非零值。 函数功能: 这个API函数用来从消息队列中“摘取”一个消息,放到lpMsg所指的变量里。(注:如果所取窗口的消息队列中没有消息,则程序会暂停在GetMessage() 函数里,不会返回。)再通俗一点讲解GetMessage函数:当程序执行GetMessage()的时候,会检查消息队列,如果有消息在消息队列里,它取出该消息,将该消息填充到lpMsg所指的MSG结构,并返回TRUE值。如果此时消息队列里没有消息(消息队列为空),它会将线程阻塞,也就是将控制权交给系统,直到消息队列中有内容时,才唤醒线程继续执行。对于GetMessage()函数,还有一点需要说明,就是当从消息队列中取出的消息是WM_QUIT时,函数返回值是0。我们一般利用这一点退出消息循环,结束程序。 如语句:while(GetMessage(&msg,NULL,0,0)2 )、PeekMessage 函数原型: BOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg); 参数: lpMsg、hWnd、wMsgFilterMin、wMsgFilterMax这四个参数的意义和GetMessage对应参数的意义相同,在此不再赘述。wRemoveMsg:这个参数决定读消息时是否删除消息,可选值有PM_NOREMOVE和PM_REMOVE。如果您选PM_NOREMOVE,执行该函数后消息仍然留在消息队列(我称为读消息);如果您选PM_REMOVE,执行该函数后将在消息队列中移除该消息(同GetMessage())。 返回值: 消息队列中有消息,返回值为TRUE;消息队列中没有消息,返回值为FALSE。 函数功能: PeekMessage()也是从消息队列中取消息,但它是GetMessage()不同,主要在以下两点: (一)、GetMessage()只能从消息队列中取走消息,也就是说,GetMessage()执行后,该消息将从消息队列中移除。PeekMessage()可以从消息队列中取走消息。也可以读消息,让消息继续留在消息队列里。 (二)、当消息队列中没有消息时,GetMessage()将会阻塞线程,等待消息;而PeekMessage()与GetMessage()不同,它执行后会立刻返回,消息队列中有消息时,返回值为TRUE;消息队列中没有消息时,返回值为FALSE。 3 )、WaitMessage 函数原型: BOOL WaitMessage(VOID); 函数功能: 这个函数的作用是当消息队列中没有消息时,将控制权交给其它线程。该函数将会使线程挂起,直到消息队列中又有新消息。这个函数专门和PeekMessage配合使用,当消息队列中没有消息时,挂起线程,等待消息队列中新消息的到来,这样可以减轻CPU的运算负担。 4 )、TranslateMessage 函数原型: BOOL TranslateMessage(CONST MSG*lpMsg); 参数: IpMsg:指向MSG结构的指针,该结构是函数GetMessage或PeekMessage从消息队列里取得的消息。 函数功能:该函数将虚拟键消息转换为字符消息。字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出。什么是虚拟键码呢?Windows为了方便输入管理,减少程序对设备的依赖性,将键盘上所有的按键都用一个两位十六进制数对应,这些数称为虚拟键码。虚拟键码一般以VK_开头,如:Esc键对应的虚拟键码是VK_ESCAPE;空格键对应的虚拟键码是VK_SPACE;VK_LWIN与左边的Windows徽标键相对应。当一个按键被按下时,会触发WM_KEYDOWN消息, WM_KEYDOWN消息的wParam参数值就是虚拟键值。通过这个值就可以判断哪个键被按下了。为什么我们要把虚拟键码转换为字符码呢?比如我们按下了A键,此时我们得到的字符可能是A,也可能是小写的a,这由当时的大写状态(Caps Lock)以及是否同时按下了Shift键有关。TranslateMessage()函数的作用就是不用我们考虑这些问题,而是根据这些情况,自动返回一个ASCII码值,以方便用户使用。并不是所有的虚拟键码值都会Translate成字符码。字母、数字键都有字符码相对应,而像方向箭头键、F1F12功能键这些按键就没有字符码相对应。当虚拟键码需要转化成字符码时,TranslateMessage()函数就在消息队列里放一条WM_CHAR消息,WM_CHAR消息的wParam参数值就是转换后的ASCII码值。 5)、DispatchMessage 函数原型: LONG DispatchMessage(CONST MSG *lpmsg); 函数功能:它的作用很简单,就是分派消息到窗口的消息处理函数去执行。了解了这5个函数,消息循环这段代码就不难理解: GetMessage()从消息队列中取消息,对取出的消息进行转换(TranslateMessage),对于能够将虚拟键码转化成字符码的消息,会在消息队列里放一条WM_CHAR消息,最后将消息发送到相应的消息处理函数进行处理。循环执行这个处理过程,直到收到WM_QUIT消息,才退出循环,结束程序。 3、进一步深入理解Windows消息/消息循环 写法1MSG msg;while(GetMessage(&msg,NULL,0,0)/从消息队列中取消息 TranslateMessage (&msg); /转换消息 DispatchMessage (&msg); /派发消息/消息循环 写法2MSG msg;while(true) if(PeekMessage(&msg,NULL,0,0,PM_REMOVE) /从消息队列中取消息 if(msg.message = WM_QUIT) break; TranslateMessage (&msg); /转换消息 DispatchMessage (&msg); /派发消息 else WaitMessage(); 上述代码段关于消息循环的两种写法PeekMessage处理消息循环比GetMessage还要灵活,尤其体现在游戏编程中。游戏编程者不希望玩家在没有键盘或鼠标输入时游戏是静止不动的,他们希望怪兽从后面冲出来,围攻玩家,追捕玩家。为了做到这样的效果,需要这样一种消息循环:当遇到需要处理的消息时去处理消息,其余的时间都让程序代码自动产生激烈的场面。 4、队列消息和非队列消息4、队列消息和非队列消息Windows把消息分为两种:一种是需要立即处理的消息,另一种是不需要立即处理的消息。对于需要立即处理的消息,Windows直接把它送给窗口的消息处理函数进行处理,这类消息我们叫做非队列消息;而对于不需要立即处理的消息,Windows会把它发送给应用程序的消息队列进行排队,由应用程序逐个进行处理,我们把这类消息叫做队列消息。为了更清楚地说明这个问题,我们参看图1:图1 图1的解释: 1)、Windows操作系统有一个消息队列,它存放操作系统收到的消息。如:当按键被按下,键盘会发送一个消息到操作系统的消息队列。2)、操作系统把系统消息队列中的消息分派到各个应用程序的消息队列。如果它是第1个应用程序的消息,操作系统把它发给第1个应用程序,把它放在第1个应用程序的消息队列;如果它是第2个应用程序的消息,发送给第2个程序的消息队列。3)、应用程序的消息循环从自己的消息队列中取消息,取出的消息调用窗口过程函数进行处理。4)、PostMessage是寄送消息,函数执行后立即返回。寄送的消息是队列消息,放在程序的消息队列中排队处理。一般来说,新寄送的消息排在消息队列的末尾,这样可以保证窗口以先进先出的顺序处理消息。SendMessage是发送消息,它发出的消息是非队列消息,直接调用窗口过程函数处理。SendMessage函数一直等消息处理完成后才返回。 我们有必要再专门学习一下SendMessage(非队列)和PostMessage(队列)函数。 SendMessage的函数原型: LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); 这个函数向窗口发送一条消息,一直等到消息被处理之后才返回。也就是说,接收消息的窗口的窗口函数立即被调用。函数的返回值由接收消息的窗口的窗口函数返回。 PostMessage的函数原型: BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); 该函数把一条消息放置到创建hWnd窗口的线程的消息队列中,该函数不等消息被处理就马上将控制返回。从上面这两个函数,我们可以看出消息的发送方式和寄送方式的区别:被发送的消息会被立即处理,处理完毕后函数才返回;被寄送的消息不会被立即处理,他被放到一个先进先出的队列中,按次序等候处理,而且函数放置消息后立即返回。以寄送方式发送的消息通常是与用户输入事件相对应的,因为这些事件不是十分紧迫,可以进行缓冲处理,例如鼠标、键盘消息都是寄送消息。应用程序调用系统函数,系统一般会发送非队列消息。例如,当程序调用SetWindowPos,系统会发送WM_WINDOWPOSCHANGED消息。5、WM_COMMAND和WM_NOTIFY1、问题的提出: 在Windows3.x中,不存在WM_NOTIFY消息,控制子窗口的通知消息同菜单的命令消息及加速键消息一样,均使用WM_COMMAND来发送,此时,根据WM_COMMAND消息传递的做法,可知道含有如下的传递结构: wParam high-order : Notify Code :(如TTN_NEEDTEXT)wParam low-order : ControlIDlParam : ControlHandle 使用上述结构进行消息的传递时,如果一个通知消息有一些附加的消息需要发送时(如传递LVN_COLUMNCLICK时可能需要附加传送如点击的是那一列等信息),又或者需要获取鼠标双击的list control 的某一具体ITEM时,因为WM_COMMAND仅能传递如上的参数,故无法做到。 2、解决办法 通过把lParam指向某些特定结构体以附加更多的信息。 以获取双击list control列表的某一具体项为例: 假如wParam 的ControlID 为list control 的ID时候,lParam指向结构体:typedef struct tagNMLISTVIEW NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; NMLISTVIEW, *LPNMLISTVIEW;这样,就实现了附加参数的传递,类似的做法在Windows3.x中随处可见。Windows32中的解决方案,Windows3.x的解决方案各自为政,没有统一性,为了解决这个问题,Window32中引入了一个新的消息,即WM_NOTIFY消息来解决这个问题,它将所有的这些消息采用一个统一的架构进行处理,为了与以前的处理方式兼容,上述那些特殊的消息仍然存在,它们在实质上也是相同的。WM_NO

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论