Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(一)

简介: Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息

上一章节中我们带大家编写了第一个Windows程序,并且带大家学习了注册窗口,创建窗口,这一章中我们来学习Windows消息,学习对消息循环处理的原理,并且带领大家学习一些常见的消息。

一.消息基础

1.消息概念及其作用

在Windows平台下,消息组成:

  • 窗口句柄
  • 消息ID
  • 消息的两个附加信息
  • 消息产生的时间
  • 产生消息时,鼠标的位置
    我们来看看微软定义的消息结构到底是怎样的:
typedef struct tagMSG{
  HWND hwnd;         //接收消息的窗口句柄
  UINT message;      //消息类型(消息标识符)
  WPARAM wParam;     //关于消息的附加消息
  LPARAM lParam;     //关于消息的附加消息
  DWORD time;        //消息的产生时间
  POINT pt;          //发布消息时的光标位置(以屏幕坐标系表示)
}

MSDN官方文档msg结构

2.消息的作用

当系统通知窗口工作时,就采用消息的方式派发给窗口的消息处理函数,以完成窗口的工作。

3.派发消息的过程

  • 1.根据消息的窗口句柄,找到相对应的窗口
  • 2.找到保存窗口数据的内存
  • 3.找到消息处理函数
  • 4.Wndproc(…){
    回到自己的代码(处理消息);
    }

4.回调函数(窗口处理函数)

每个窗口都必须有回调函数。在应用程序中定义的回调函数,用于处理发送到窗口的消息WNDPROC类型定义指向此回调函数的指针,wndproc名称时应用程序中定义的函数名称的占位符。

我们来看看官方定义的窗口处理函数的原型:

LRESULT CALLBACK WindowProc(
  HWND hwnd;      //窗口句柄
  UINT uMsg;      //消息ID
  WPARAM wParam;  //消息附加参数
  LPARAM lParam;  //消息附加参数
){......};

MSDN官方文件解释WNDPROC函数

在这里为大家解释:
LRESULT是程序返回到Windows的整数数值。它包含程序对特定消息的响应。此值的含义取决于消息代码。
CALLBACK是函数的调用约定。

当系统通知窗口时,会调用窗口处理函数,同时将消息ID等附加消息传给窗口处理函数,在窗口处理函数中,不处理的消息,使用缺省窗口处理函数(如DefWindowProc。

5.浅谈消息相关函数

GetMessage函数–获取本进程的消息

Bool GetMessage(
  LPMSG lpMsg;       //指向MSG结构的指针,该结构从线程的消息队列中结构消息
  HWND hwnd;         //要检索其消息的窗口句柄,窗口必须属于当前线程
  UINT wMsgFilterMin;  //要检索的最低消息值的整数值
  UINT wMsgFilterMax;  //要检索的最高消息值的整数值
);

TranslateMessage函数–翻译消息

BOOL TranslateMessage(
  const MSG* lpMsg;
);

二.消息循环处理的原理

1.消息循环处理的阻塞

GetMessage函数: 从系统中获取消息,将消息从系统中移除,阻塞函数。当无系统消息时,等候下一条消息。

PeekMessage函数: 以查看的方式从系统中获取消息,可以不将消息从系统中移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。

BOOL PeekMessage(
  LPMSG lpMsg;       //指向接收信息的MSG结构的指针
  HWND hwnd;         //要检索其消息的窗口句柄,窗口必须属于当前线程
  UINT wMsgFilterMin; //要检查的消息范围的第一条消息的值
  uint wMsgFilterMax; //要检查的消息范围的最后一条消息的值
  UINT wRemoveMsg;  //指定如何处理消息(删除/不删除消息等)
}

MSDN官方文档解释PeekMessage函数

学习了PeekMessage函数之后我们来看看我们在上一章中写的消息循环的代码:

MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd,NULL, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int) msg.wParam;
}

那么我们就会发现,我们在消息循环中只使用GetMessage函数的话,那么效率就会很低,因为GetMessage函数经常阻塞。在这里我们学习了PeekMessage函数之后,我们就可以将PeekMessage函数当作侦察兵,先让他去看看有没有消息,如果有消息的话,我们就可以在再去GetMessage等函数。

看看我们优化后的代码:

while (1) {
    if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
      if (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      else {
        return 0;
      }
    }
    else {
      //在空闲的时候,我们想让它做什么就可以填在这里
    }
  }

2.在应用程序中调出控制台调试程序

在我们编写控制台程序的时候,我们可以随时输出来调试程序,那么我们在编写Windows程序的时候,我们无法在程序中直接调试程序,那么我们就需要调出控制台来调试我们的程序,在这里给出在我们编写的Windows程序中调出控制台来调试代码的方法:

  • 首先,我们需要定义一个全局变量(HANDLE)类型,用于接收标准输出句柄
  • 使用AllocConsole()函数在Windows程序中增加DOS窗口
  • 使用GetstdHandle函数接收标准输出句柄,并且用之前定义的HANDLE类型的全局变量接收
    使用示例:
HANDLE g_hOutput = 0;
...
AllocConsole();
g_hOutput = GetstdHandle(STD_OUTPUT_HANDLE);

其中,sprintf函数的作用是:将设置格式的数据写入字符串。

我们来看看作用效果:

3.发送消息

SendMessage函数:发送消息,会等候消息的处理结果

LRESULT SendMessage(
  HWND hWnd;      //窗口的过程句柄将接收消息
  UINT Msg;       //要发送的消息
  WPARAM wParam;  //其他的消息特定信息
  LPARAM lParem;  //其他的消息特定信息
);

返回值(LRESULT类型):返回值指定消息处理的结果,这取决于发送的消息。

MSDN官方文档解释SendMessage函数

PostMessage函数:投递消息,消息发出后立刻返回,不等候消息的处理结果

BOOL PostMessage(
  HWND hWnd;             //窗口的句柄,窗口过程是接收消息
  UINT Msg;              //要发布的消息
  WPARAM wParam;         //其他的消息特定信息
  LPARAM lParam;         //其他的消息特定消息
);

MSDN官方文档解释PostMessage函数

这里关于两个发送消息函数的不同,大家可以看文档,本章后面的消息队列也会从实操角度讲到。

4.消息分类

  • 系统消息–ID范围(0~0x03FF)(1024个)
  • 由系统定义的消息,可以在程序中直接使用
  • 用户自定义消息–ID范围(ox400~0x7FFF)(31743个)
  • 由用户自己定义,满足用户自己的需求,由用户自己发出消息,自己处理
  • 自定义消息宏:WM_USER(0x400)




相关文章
|
Shell 开发者 Windows
windows 10中将任意程序添加进鼠标右键菜单里面
windows 10中将任意程序添加进鼠标右键菜单的详细步骤
232 0
windows 10中将任意程序添加进鼠标右键菜单里面
|
7月前
|
人工智能 机器人 测试技术
【windows批处理batch】.bat文件循环判断语句
【windows批处理batch】.bat文件循环判断语句
|
2月前
|
Windows
Windows 11 鼠标右键可选择 cmd 命令行选项
Windows 11 鼠标右键可选择 cmd 命令行选项
53 0
windows10为何鼠标右键失灵,桌面右键一直转圈的解决
windows10为何鼠标右键失灵,桌面右键一直转圈的解决
1104 0
|
Windows
【windows批处理batch】.bat文件循环判断语句
【windows批处理batch】.bat文件循环判断语句
453 0
|
消息中间件 Windows
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(四)
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息
|
消息中间件 Windows
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(三)
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(三)
|
27天前
|
网络安全 Windows
Windows server 2012R2系统安装远程桌面服务后无法多用户同时登录是什么原因?
【11月更文挑战第15天】本文介绍了在Windows Server 2012 R2中遇到的多用户无法同时登录远程桌面的问题及其解决方法,包括许可模式限制、组策略配置问题、远程桌面服务配置错误以及网络和防火墙问题四个方面的原因分析及对应的解决方案。
|
1月前
|
监控 安全 网络安全
使用EventLog Analyzer日志分析工具监测 Windows Server 安全威胁
Windows服务器面临多重威胁,包括勒索软件、DoS攻击、内部威胁、恶意软件感染、网络钓鱼、暴力破解、漏洞利用、Web应用攻击及配置错误等。这些威胁严重威胁服务器安全与业务连续性。EventLog Analyzer通过日志管理和威胁分析,有效检测并应对上述威胁,提升服务器安全性,确保服务稳定运行。
|
1月前
|
监控 安全 网络安全
Windows Server管理:配置与管理技巧
Windows Server管理:配置与管理技巧
76 3