`

Windows的消息机制

阅读更多
Windows是一个消息(Message)驱动系统。Windows的消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。应用程序想要实现的功能由消息来触发,并且靠对消息的响应和处理来完成。
       Windows系统中有两种消息队列:系统消息队列和应用程序消息队列。计算机的所有输入设备由Windows监控。当一个事件发生时,Windows先将输入的消息放入系统消息队列中,再将消息拷贝到相应的应用程序消息队列中。应用程序的消息处理程序将反复检测消息队列,并把检测到的每个消息发送到相应的窗口函数中。这便是一个事件从发生至到达窗口函数必须经历的过程。
       必须注意的是,消息并非是抢占性的,无论事件的缓急,总是按照到达的先后派对,依次处理(一些系统消息除外),这样可能使一些实时外部事件得不到及时处理。

Windows中的消息是放在对应的进程的消息队列里的。可以通过GetMessage取得,并且对于一般的消息,此函数返回非零值,但是对于WM_QUIT消息,返回零。可以通过这个特征,结束程序。当取得消息之后,应该先转换消息,再分发消息。所谓转换,就是把键盘码的转换,所谓分发,就是把消息分发给对应的窗口,由对应的窗口处理消息,这样对应窗体的消息处理函数就会被调用。两个函数可以实现这两个功能:TranslateMessage和DispatchMessage。
       另外,需要注意,当我们点击窗口的关闭按钮关闭窗口时,程序并没有自动退出,而是向程序发送了一个WM_DESTROY消息(其实过程是这样的,首先向程序发送WM_CLOSE消息,默认的处理程序是调用DestroyWindow销毁窗体,从而引发WM_DESTROY消息),此时在窗体中我们要响应这个消息,如果需要退出程序,那么就要向程序发送WM_QUIT消息(通过PostQuitMessage实现)。一个窗体如果想要调用自己的消息处理函数,可以使用SendMessage向自己发消息。      
        如上所述,大部分(注意是大部分)的消息是这样传递的:首先放到进程的消息队列中,之后由GetMessage取出,转换后,分发给对应的窗口。这种消息成为存储式消息。存储式消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP讯息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出。存储式消息还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。但是也有的消息是直接发送给窗口的,它们被称为非存储式消息。例如,当WinMain调用CreateWindow时,Windows将建立窗口并在处理中给窗口消息处理函数发送一个WM_CREATE消息。当WinMain调用ShowWindow时,Windows将给窗口消息处理函数发送WM_SIZE和WM_SHOWWINDOW消息。当WinMain调用UpdateWindow时,Windows将给窗口消息处理函数发送WM_PAINT消息。

一、引言
  
  随着Windows操作系统的不断推广,众多软件开发包都提供有开发基于Windows平台应用软件的功能。虽然这些开发包不尽相同,流行的有Visual C++、Visual Basic、Delphi、C++ Builder 等多种,但由这些不同语言开发的软件有一点却是相同的--都是运行于Windows 操作平台,都必须接受Windows 的运行机制。作为Windows 操作系统灵魂的消息机制也就必然为众多用不同语言开发的Windows操作系统下运行的应用程序所接受。因此,要编写深入的Windows程序,就必须对Windows的运行机制有很好的认识和理解。本文下面将对Windows操作系统下的消息运行机制做较为深入的剖析。
  
  二、Windows事件驱动机制
  
  我们当中不少使用VC、Delphi等作为开发语言的程序员是一步步从DOS下的Basic、C++中走过来的,而且大多在刚开始学习编程时也是先从DOS下的编程环境入手的,因此在习惯了DOS下的过程驱动形式的顺序程序设计方法后,往往在向Windows下的开发环境转型的过程中会对Windows所采取的事件驱动方式感到无法适应。因为DOS和Windows这两种操作系统的运行机制是截然不同的,DOS下的任何程序都是使用顺序的、过程驱动的程序设计方法。这种程序都有一个明显的开始、明显的过程以及一个明显的结束,因此通过程序就能直接控制程序事件或过程的全部顺序。即使是在处理异常时,处理过程也仍然是顺序的、过程驱动的结构。而Windows的驱动方式则是事件驱动的,即程序的流程不是由事件的顺序来控制,而是由事件的发生来控制,所有的事件是无序的,所为一个程序员,在编写程序时,并不知道用户会先按下哪个按纽,也就不知道程序先触发哪个消息。因此我们的主要任务就是对正在开发的应用程序要发出的或要接收的消息进行排序和管理。事件驱动程序设计是密切围绕消息的产生与处理而展开的,一条消息是关于发生的事件的消息。
  
  三、Windows的消息循环
  
  Windows操作系统为每一个正在运行的应用程序保持有一个消息队列。当有事件发生后,Windows并不是将这个激发事件直接送给应用程序,而是先将其翻译成一个Windows消息,然后再把这个消息加入到这个应用程序的消息队列中去。应用程序需要通过消息循环来接收这些消息。在MFC中使用了对WinAPI进行了很好封装的类库,虽然可以为编程提供一个面向对象的界面,使Windows程序员能够以面象对象的方式进行编程,把那些进行SDK编程时最繁琐的部分提供给程序员,使之专注于功能的实现,但是由于引入了很好的封装特性,使我们不能直接操纵部分核心代码。对于消息的循环和接收也只是通过类似于下面的消息映射予以很简单的表示:
  
  BEGIN_MESSAGE_MAP(CTEMMSView, CFormView)
  //{ { AFX_MSG_MAP(CTEMMSView)
  ON_WM_LBUTTONDOWN()
  ON_COMMAND(ID_OPENDATA, OnOpenData)
  ON_WM_TIMER()
  ON_WM_PAINT()
  //} } AFX_MSG_MAP
  END_MESSAGE_MAP()
  
  虽然上述消息映射在编程过程中处理消息非常简练方便,但显然是难于理解消息是如何参与循环和分发的。因此有必要通过SDK(Software Developers Kit,软件开发工具箱)代码深入到被MFC封装的Windows编程的核心中来研究其具体是如何工作的。在SDK编程中,一般是在Windows应用程序的入口点WinMain函数中添加处理消息循环的代码以检索Windows送来的消息,然后WinMain再把这些消息分配给相应的窗口函数并处理它们:
  
  ……
  MSG msg; //定义消息名
  while (GetMessage (& msg, NULL, 0, 0))
  {
  TranslateMessage (& msg) ; //翻译消息
  DispatchMessage (& msg) ; //撤去消息
  }
  return msg.wParam ;
  
  上述几句虽然简单但却是所有Windows程序的关键代码,担负着获取、解释和分发消息的任务,下面就重点对其功能和作用进行分析:
  
  MSG结构在头文件中定义如下:
  
  typedef struct tagMSG
  {
  HWND hwnd;
  UINT message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD time;
  POINT pt;
  } MSG, *PMSG;
  
  其数据成员的具体意义如下:
  
  hwnd:消息将要发送到的那个窗口的句柄,用这个参数可以决定让哪个窗口接收消息。
  message:消息号,它唯一标识了一种消息类型。每种消息类型都在Windows文件进行了预定义。
  wParam:一个32位的消息参数,这个值的确切意义取决于消息本身。
  lParam:同上。
  time:消息放入消息队列中的时间,在这个域中写入的并非当时日期,而是从Windows启动后所测量的时间值。Windows用
  这个域来使用消息保持正确的顺序。
  pt:消息放入消息队列时的鼠标坐标。
  
  消息循环以GetMessage调用开始,它从消息队列中取出一个消息。该函数的四个参数可以有控制地获取消息,第一个参数指定要接收消息的MSG结构的地址,第二个参数表示窗口句柄,一般将其设置为空,表示要获取该应用程序创建的所有窗口的消息;第三、四参数用于指定消息范围。后面三个参数被设置为默认值,用于接收发送到属于这个应用程序的任何一个窗口的所有消息。在接收到除WM_QUIT之外的任何一个消息后,GetMessage()返回TRUE;如果GetMessage收到一个WM_QUIT消息,则返回FALSE以退出消息循环,终止程序运行。因此,在接收到WM_QUIT之前,带有GetMessage()的消息循环可以一直循环下去。当除WM_QUIT的消息用GetMessage读入后,首先要经过函数TranslateMessage()对其进行解释,但对大多数消息来说并不起什么作用。这里起关键作用的是DispatchMessage()函数,把由GetMessage获取的Windows消息传送给在MSG结构中为窗口所指定的窗口过程。在消息处理函数处理完消息之后,代码又循环到开始去接收另一个消息,这样就完成了一个完整的消息循环。
  
  由于Windows操作系统是一种非剥夺式多任务操作系统。只有在应用程序主动交出CPU控制权后,Windows才能把控制权交给其他应用程序。在消息循环中,一定要有能交出控制的系统函数才能实现协同式多任务操作。能完成该功能的只有GetMessage、PeekMessage和WaitMessage这三个函数,如果在应用程序中长期不去调用这三个函数之一其他任务则无法执行。GetMessage函数在找不到等待应用程序处理的消息时,会自动交出控制权,由Windows把CPU的控制权交给其他等待获取控制权的应用程序。由于任何Windows应用程序都含有一个消息循环,这种隐式交出控制权的方式可以保证合并各个应用程序共享控制权。一旦发往该应用程序的消息到达应用程序队列,即开始执行GetMessage语句的下一条语句。使用GetMessage函数的消息循环在消息队列中没有消息时将等待,如果需要,可以利用这段时间进行I/O端口操作等耗时操作,不过需要在消息循环中使用PeekMessage函数来代替GetMessage。使用PeekMessage的方法同GetMessage类似,下面是一段使用PeekMessage函数的消息循环的典型例子:
  
  MSG msg;
  BOOL bDone=FALSE;
  do{
  if(PeekMessage(& msg,NULL,0,0,PM_REMOVE)){
  if(msg.message==WM_QUIT)
  bDone=TRUE;
  else{
  TranslateMessage(& msg);
  DispatchMessage(& msg);
  }
  }
  //无消息处理,进行长时间操作
  else{
  ……//长时间操作
  }
  } while(!bDone)
  ……
  
  无论应用程序消息队列中是否有消息,PeekMessage函数都立即返回,如果希望等待新消息入队,可以利用无返回值的函数WaitMessage配合PeekMessage进行消息循环。
  
  四、对Windowds消息的处理
  
  窗口过程处理消息通常以switch语句开始,对于它要处理的每一条消息ID都跟有一条case语句,这在功能上同MFC的消息映射有些类似:
  
  switch(uMsgId)
  {
  case WM_TIMER:
  //对WM_TIMER定时器消息的处理过程
  return 0;
  case WM_LBUTTONDOWN:
  //对WM_ LBUTTONDOWN鼠标左键单击消息的处理过程
  ruturn 0;
  ……
  default:
  //其他消息由这个默认处理函数来处理
  return DefWindowProc(hwnd,uMsgId,wParam,lParam);
  }
  
  在处理完消息后必须返回0,这很重要,否则Windows将要不停地重试下去。对于那些在程序中不准备处理的消息,窗口过程会把它们都扔给DefWindowProc进行缺省处理,而且还要返回那个函数的返回值。在消息传递层次中,可以认为DefWindowProc函数是最顶层的函数。该函数发出WM_SYSCOMMAND消息,由系统执行Windows环境中多数窗口所公用的各种通用操作,如更新窗口的正文标题等等。 在MFC下可以用下述部分代码实现与上述SDK代码相同的功能:
  
  BEGIN_MESSAGE_MAP(CTEMMSView, CFormView)
  //{ { AFX_MSG_MAP(CTEMMSView)
  ON_WM_LBUTTONDOWN()
  ON_WM_TIMER()
  //} } AFX_MSG_MAP
  END_MESSAGE_MAP()
  
  小结:Windows环境提供有非常丰富的系统资源,在这个基础上可以编制出能满足各种各样目标功能的应用系统。要深入Windows编程就必须首先对Windows系统的运行机理有很好的认识,本文仅针对Windows的一种重要运行机制--消息机制作了较深入的剖析和阐述。对培养在Windows下的编程思想有一定的帮助。对某些相关问题的详细论述可以参考MSDN在线帮助的" SDK Reference" 部分。
分享到:
评论

相关推荐

    Windows消息机制.pdf

    Windows消息机制是Windows操作系统的核心组成部分之一,它允许应用程序之间以及应用程序内部进行通信和数据交换。Windows消息是一个通知,表示有一个特定的事件发生了,例如鼠标点击、按键按下、窗口尺寸改变等。...

    Windows消息机制

    ### Windows消息机制详解 #### 一、Windows消息机制概述 Windows消息机制是Windows操作系统的核心组成部分之一,用于在各个进程或线程之间传递信息。通过这一机制,不同的应用程序或线程可以互相通信,实现数据...

    Windows 消息机制

    **Windows消息机制** Windows消息机制是Windows操作系统中用于进程间通信和线程间通信的核心机制。它是基于事件驱动的,允许应用程序对用户交互、系统事件以及其他进程发送的通知进行响应。在Windows程序设计中,...

    Windows消息机制要点

    Windows消息机制是Windows操作系统核心组件之一,用于处理应用程序与用户之间的交互。这一机制确保了GUI(图形用户界面)程序的响应性和同步性。下面将详细解释Windows消息机制的关键要点。 首先,每个窗口都有一个...

    windows的消息机制

    ### Windows的消息机制详解 ...通过以上内容的学习,我们可以对Windows消息机制有一个初步的认识。消息机制是Windows应用程序开发的核心之一,掌握好这部分内容对于编写高质量的Windows应用程序至关重要。

    windows消息机制

    Windows消息机制是操作系统的核心组成部分,它是Windows应用程序之间以及应用程序与操作系统之间进行通信的主要方式。在Windows环境下,所有的用户界面交互,如键盘输入、鼠标点击、窗口移动等,都会被转换成特定的...

    Windows消息机制视频

    Windows消息机制是Windows操作系统核心部分的一个重要组成部分,它在应用程序与操作系统之间起到了桥梁的作用,使得程序可以接收并处理来自用户的输入和其他系统事件。这个视频教程应该是深入解析了这一主题,帮助...

    Windows消息机制简介

    windows消息机制简单介绍,对消息过程的简单介绍和解释

    Windows消息机制及HOOK应用

    ### Windows消息机制及HOOK应用 #### 一、Windows事件驱动机制 Windows操作系统采用了与DOS截然不同的编程模型。在DOS环境下,程序通常按照顺序执行或者基于过程调用来驱动程序流程,而Windows则采取了事件驱动的...

    MFC Windows 消息机制 资料

    MFC Windows 消息机制 资料 MFC Windows 消息机制是 Windows 操作系统的核心机制之一,它负责处理用户输入、窗口状态变化和其他事件的消息通知。下面是对该机制的详细解释和分析: 消息的组成 一个消息由三个部分...

    WinSDK编程(续)_windows消息机制

    本文将深入探讨Windows消息机制的概念、工作原理以及如何在实际编程中使用。 一、Windows消息机制概述 Windows消息机制是Windows操作系统提供的一种事件驱动模型。它通过消息队列、消息循环和消息处理函数来确保...

    键盘钩子-windows消息机制-抓取用户按下的每一个按键

    首先,我们要了解Windows消息机制。在Windows编程中,应用程序通过消息循环接收和处理用户输入、系统事件等。当用户按下键盘时,操作系统会创建一个键盘消息(如WM_KEYDOWN或WM_KEYUP),并将该消息放入与应用程序...

    windows消息机制及其应用.doc

    Windows消息机制是Windows操作系统核心组成部分,它在编程中起着至关重要的作用,特别是在构建交互式应用程序时。消息机制是Windows应用程序的基础,它负责处理用户与应用程序之间的交互,确保程序能够及时响应用户...

    Windows消息机制实例代码

    本文将深入探讨Windows消息机制,并通过一个VB.NET的实例代码来阐述`WM_COPYDATA`消息的使用。 Windows消息机制是基于消息队列的事件驱动模型。当用户与窗口进行交互,如点击鼠标、按下键盘或执行其他操作时,系统...

    windows的多线程消息机制

    首先,我们来看消息循环,它是Windows消息机制的核心。消息循环通常由`GetMessage`和`DispatchMessage`函数组成。`GetMessage`函数从消息队列中取出一个消息并将其存储在`MSG`结构中,如果队列中有消息,它会阻塞...

Global site tag (gtag.js) - Google Analytics