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)




相关文章
|
10月前
|
Shell 开发者 Windows
windows 10中将任意程序添加进鼠标右键菜单里面
windows 10中将任意程序添加进鼠标右键菜单的详细步骤
181 0
windows 10中将任意程序添加进鼠标右键菜单里面
|
2月前
|
人工智能 机器人 测试技术
【windows批处理batch】.bat文件循环判断语句
【windows批处理batch】.bat文件循环判断语句
|
8月前
|
Windows
2.6 Windows驱动开发:使用IO与DPC定时器
本章将继续探索驱动开发中的基础部分,定时器在内核中同样很常用,在内核中定时器可以使用两种,即IO定时器,以及DPC定时器,一般来说IO定时器是DDK中提供的一种,该定时器可以为间隔为N秒做定时,但如果要实现毫秒级别间隔,微秒级别间隔,就需要用到DPC定时器,如果是秒级定时其两者基本上无任何差异,本章将简单介绍`IO/DPC`这两种定时器的使用技巧。首先来看IO定时器是如何使用的,IO定时器在使用上需要调用`IoInitializeTimer`函数对定时器进行初始化,但需要注意的是此函数每个设备对象只能调用一次,当初始化完成后用户可调用`IoStartTimer`让这个定时器运行,相反的调用`I
56 0
2.6 Windows驱动开发:使用IO与DPC定时器
|
8月前
windows10为何鼠标右键失灵,桌面右键一直转圈的解决
windows10为何鼠标右键失灵,桌面右键一直转圈的解决
1027 0
|
Windows
【windows批处理batch】.bat文件循环判断语句
【windows批处理batch】.bat文件循环判断语句
272 0
|
消息中间件 Windows
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(四)
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息
|
消息中间件 Windows
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(三)
Windows消息,消息循环的处理,消息队列,键盘消息,鼠标消息,定时器消息(三)
|
2月前
|
Linux Windows
Windows Server 下文件同步
Windows Server 下文件同步
35 0
|
19天前
|
编解码 安全 网络安全
RealVNC的 VNC server在windows7系统下无法正确运行
在Windows 7上运行旧版VNC Server(如4.1.2)可能存在兼容性问题,但可通过调整配置解决。步骤包括:安装VNC Server,设置兼容性模式(选择Windows XP SP3),启动VNC Server,配置VNC连接参数。若遇到问题,检查防火墙设置,确保系统更新,并考虑升级到新版VNC Server以提高性能和兼容性。
|
2月前
|
开发框架 .NET API
在Windows Server 2008 R2上运行.Net 8应用
在Windows Server 2008 R2上成功运行.Net 8程序,需安装三个补丁:Windows Server 2008 R2 SP1 (KB976932)是基础更新;VC_redist.x64提供MSVC库支持;KB3063858解决.NET运行时加载`kernel.dll`的路径问题。KB3063858可能需要KB2533623。详细信息和下载链接在文中给出。

热门文章

最新文章