Mark一下:Windows消息响应机制
in 代码 with 3 commentsand 557 read

Mark一下:Windows消息响应机制

in 代码 with 3 commentsand 558 read

Windows是一个消息(Message)驱动系统。不同于DOS系统的程序逐条执行的方式,Windows的消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。
1.jpg
Windows应用程序想要实现的功能由消息来触发,并且靠对消息的响应和处理来完成。必须注意的是,消息并非是抢占性的,无论事件的缓急,总是按照到达的先后派对,依次处理(一些系统消息除外),这样可能使一些实时外部事件得不到及时的处理。

Windows消息队列的类型

Windows的应用程序一般包含窗口(Window),它主要为用户提供一种可视化的交互方式,窗口是总是在某个线程(Thread)内创建的。Windows系统通过消息机制来管理交互,消息(Message)被发送,保存,处理,一个线程会维护自己的一套消息队列(Message Queue),以保持线程间的独占性。队列的特点无非是先进先出,这种机制可以实现一种异步的需求响应过程。

系统消息队列

由Windows系统维护管理的消息队列,每当有消息发生时,该消息将首先被存入系统消息队列。

应用程序消息队列

Windows系统会为每个应用程序建立一个独立的消息队列,用于存放该应用程序的消息。

消息循环

每个应用程序都有一个循环机构,该循环机构则不断地重复查看程序自身的消息队列,如果队列中有消息,就将其取出并执行相应的消息处理代码,这个处理消息的循环机构称为消息循环。

Windows程序调度的基本原理

每个Windows程序启动后,就等待用户在其窗口中进行操作。每个操作会引发一个事件,就会产生一个与之对应的特定消息。该消息会被Windows系统捕获。Windows系统对捕获的消息进行分析后,会将消息传递给产生它的应用程序的消息队列,每个应用程序的消息循环机构不断地重复查看它自已的消息队列,如果队列中有消息,就将其取出并执行相应的消息处理代码, 如果队列中没有消息就等待,当队列中有消息时就又处理它,如此循环往复,直至程序结束。

3.png

Windows程序的执行逻辑

– Windows系统首先为该程序建立必备的程序环境,如定义并初始化一些全局变量,接下来就寻找并进入WinMain函数。
– WinMain是Window程序的入口点,由它控制程序的执行流程。WinMain函数依次完成以下工作:调用API函数定义并注册窗口类,创建程序窗口,显示窗口,建立消息循环,等待用户操作程序窗口。
– 用户在程序窗口中所作的每件事情都会产生一个消息,该消息会被Windows传递到该程序的消息队列中。WinMain中的消息循环会不断地从本程序的消息队列中获取消息,并将其传递给该窗口的窗口处理函数,由窗口处理函数对消息进行处理,实现相应的程序功能。

程序入口点

DOS平台的C程序的入口点是main()函数,在WINDOW的C++程序的入口点是WinMain()函数。其定义形式为:

int APIENTRY WinMain(
  HINSTANCE hInstance,// 实例句柄,当程序在WINDOWS下运行时,它唯一地标识该程序
  HINSTANCE hPrevInstance,// 当程序在WINDOWS下有多个副本运行时,它标识该程序的前一个副本
  LPSTR     lpCmdLine,// 标识传给该程序的命令行参数,近似于main()函数的char *argv[ ]
 
int       nCmdShow)// 指针窗口在Window中的显示方式,其值为1-7,如:值1表示SW_SHOWNORMAL //窗口以常规显示

注册窗口类

窗口总是在窗口类的基础上创建的,窗口类标识了处理窗口消息的窗口过程,这是非常重要的。
记住:窗口总是在窗口类的基础上创建的,窗口类用于标识处理窗口消息的窗口过程。
在创建窗口之前,必须先调用RegisterClass函数登录一个窗口类,以后可以基于这个已登录的窗口创建多个窗口。
只有程序的第一个实例需要登录窗口类!

WNDCLASS     wndclass ;
    wndclass.style                 = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc    = WndProc ;// 发生在本窗口中的事件由WndProc处理,这是WinMain与窗口函数的关联!

     wndclass.cbClsExtra       = 0 ;
     wndclass.cbWndExtra     = 0 ;
     wndclass.hInstance        = hInstance ;
     wndclass.hIcon               = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor           = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName = NULL ;
     wndclass.lpszClassName = szAppName ;
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, “This program …… !", szAppName, MB_ICONERROR) ;
          return 0 ;
     }

创建窗口

hwnd = CreateWindow (
            szAppName,                           // window class name
                          TEXT ("The Hello Program"), // window caption
                          WS_OVERLAPPEDWINDOW,   // window style
                          CW_USEDEFAULT,                // initial x position
                          CW_USEDEFAULT,                // initial y position
                          CW_USEDEFAULT,                // initial x size
                          CW_USEDEFAULT,                // initial y size
                          NULL,               // parent window handle
                          NULL,               // window menu handle
                          hInstance,          // program instance handle
                          NULL
            ) ;                             // creation parameters 
  if (!hWnd)   {     return FALSE;   }                   //建立窗口失败

显示窗口

ShowWindow(hWnd, nCmdShow);// hWnd是前面创建的窗口的句柄; nCmdShow是窗口显示的方式,缺省值为1即:SW_SHOWNORMAL
UpdateWindow(hWnd);// hWnd是前面创建的窗口的句柄,该函数产生WM_PAINT消息,导致窗口被重绘

消息循环

调用UpdateWindow(hWnd);函数之后,窗口就显示在显示屏幕上,这时程序就进入了消息循环,等待用户用键盘或鼠标操作窗口,产生消息。产生的消息将被放入消息队列
4.png

while (GetMessage(&msg, NULL, 0, 0)){// 消息循环从此开始,它从消息队列中取出一条消息,WM_QUIT则退出

        TranslateMessage(&msg);// 将MSG消息进行传给WINDOWS系统,并进行一些键盘转换
        DispatchMessage(&msg);    }//再将MSG消息传给WINDOWS系统,然后WINDOWS系统将该消息传给正确的窗口过程,让它进行处理。本程序是由WndProc函数处理,处理完毕后,WndProc返windows,因为此时Windows调用还处于DispatchMessage函数,在该函数执行后,再次返回到 下一个GetMessage函数

窗口函数和消息处理

实际的动作发生在窗口函数中,窗口函数确定了在窗口的客户区域中显示些什么以及窗口函数怎样响应用户的输入。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
说明:
1、WndProc是一个回调函数
CALLBACK指定窗口函数是一个回调函数。回调就是由Windows系统调用的意思,即窗口函数是由Windows系统调用的,应用程序不必调用它。
2、窗口函数的参数
每个Windows应用程序的窗口函数都有着相同的参数表:
第1个参数hWnd用于标识接收消息的窗口句柄;
第2个参数message用于标识消息,该消息将被用于处理消息的switch结构中;
第3、4个参数wParam和lParam是message的附加信息,它们的内容随message消息而异,如鼠标消息与键盘消息的wParam和lParam参数就不一样。窗口函数主要利用这些参数响应窗口事件,实现程序功能。

窗口函数所接收的消息都是用一个数值来标识的,它就是传递给窗口过程的message参数,消息在WINDOWS.H头文件中定义,它们是以“WM_”的标识符。
一般地,在WINDOWS程序中使用switch和case结构来确定窗口函数接收的是什么消息以及如何处理它。
窗口函数不处理的消息被传给:DefWindowProc函数进行缺省处理

数据输出与WM_PAINT消息

WM_PAINT消息对于windows程序设计是极其重要的,当窗口客户区的一部分或全部变为“无效”时,将产生该消息,它导致窗口重绘。
Hellow window中窗口的类型为:
CS_HREDRAW | CS_VREDRAW;
该类型指示当窗口水平或垂直方向发生变化时,窗口将产生WM_PAINT消息致使窗口重绘。

WM_PAINT消息的处理模式:

 hdc=BeginPaint(hwnd,&ps)
         ……
         …… //进行窗口绘制的程序代码
         ……
EndPaint(hwnd,&ps);

WM_DESTROY消息与程序结束

这是一条重要的消息,它指示windows系统关闭该应用程序。
系统菜单上的close或ALT+F4都会产生该消息。
Hellow window程序通过PostQuitMessage(0);函数产生该消息。导致应用程序的关闭
5.png

评论
  1. 大佬头发是不是已经秃了

    回复
    1. @shansan

      ๛ก(ー̀ωー́ก) 
      忽然感觉头顶凉凉

      回复
      1. @shansan

        哈哈哈,我很菜的,所以我秀发还很茂密

        回复