一 Win32消息机制

1 消息机制
 
    过程驱动:程序是按照我们预先定义好的顺序执行,每执行一步,下一步都已经按照预定的顺序继续执行,直到程序结束。
     
    事件驱动:程序的执行顺序是无序的。某个时间点所执行的代码,是由外界通知。由于我们无法决定用户执行顺序,所以代码的执行也是无序。
     
    Win32的消息机制 - 事件驱动

2 Win32消息程序
 
    2.1 Win32窗口注册
    2.2 Win32窗口创建
    2.3 WIn32消息循环
     2.3.1 GetMessage

  BOOL GetMessage(LPMSG lpMsg,//存放获取到的消息数据HWND hWnd,//获取消息的窗口句柄UINT wMsgFilterMin,//消息过滤的起始消息UINT wMsgFilterMax //消息过滤的终止消息);

返回值BOOL:成功获取消息,返回TRUE,但是当获取到WM_QUIT消息时,返回FALSE。
    可以使用PostQuitMessage向窗口发送WM_QUIT消息
    MSG - 由系统填写关于消息的参数
    hWnd- GetMessage会根据hWnd值,接收由hWnd指定的窗口的消息。
    wMsgFilterMin,wMsgFilterMax - 消息过滤器,要求GetMessage接收指定范围的消息。

2.3.2 TranslateMessage
    就是将键盘消息转换成字符消息。
    1 首先检查是否是键盘按键消息     
    2 如果发现是按键消息,将根据按键,产生一个字符消息,在下一个GetMessage执行时,会收到这个消息。
     3 如果未发现按键消息,不做任何处理。

2.3.3 DispatchMessage
    根据消息数据内窗口句柄,找到这个窗口的窗口处理函数, 调用处理函数,进行消息处理。
    如果MSG中,HWND窗口句柄为空,DispatchMessage不做任何处理。
      
    2.4 Win32基本消息
      2.4.1 WM_DESTROY
         窗口销毁时的消息,可以做退出或善后处理。
      2.4.2 WM_CREATE
         窗口创建消息,是在窗口创建后,窗口处理函数收到第一条消息。
         可以在这个消息内做数据初始化/创建子窗口等。
         WPARAM wParam - 不使用
         LPARAM lParam - CREATESTRUCT指针
      2.4.3 WM_SIZE
         当窗口大小发生变化时,会收到这个消息。
         可以在这个消息中调整窗口布局。
         wParam - SIZE发生变化时的标识
     LOWORD(lParam); - 客户区的宽
         HIWORD(lParam); - 客户区的高
      2.4.4 WM_SYSCOMMAND
         系统命令消息,当点击系统菜单和按钮时,会收到。
         可以在这个消息中,提示用户保存数据等。
         wParam - 系统命令类型
         LOWORD(lParam) - 屏幕X坐标
         HIWORD(lParam) - 屏幕Y坐标

2.4.5 WM_PAINT 绘图消息
      2.4.6 键盘消息
      2.4.7 鼠标消息
      2.4.8 WM_TIMER定时器消息
     
    2.5 消息结构
      MSG - 消息结构

typedef struct tagMSG {     // msg HWND   hwnd; //消息的窗口句柄   UINT   message;//消息标示WPARAM wParam; //消息的参数,32位LPARAM lParam; //消息的参数,32位DWORD  time;//消息产生的时间POINT  pt; //消息产生时,鼠标的位置
} MSG; 

2.6 消息的获取和发送
     2.6.1 获取GetMessage/PeekMessage
         GetMessage 获取消息,阻塞函数
         PeekMessage 获取消息,非阻塞函数
     2.6.2 发送SendMessage/PostMessage
         SendMessage 发送消息并等候消息处理结束才返回。
         PostMessage 发送消息后立即返回,不关心消息处理的结果。

        LRESULT SendMessage/PostMessage(HWND hWnd,      //处理消息窗口UINT Msg,       //消息的IDWPARAM wParam,  //消息的参数LPARAM lParam );//消息的参数

3 消息组成和分类
   3.1 消息组成
      窗口句柄/消息ID/消息参数(WPARAM.LPARAM)
   3.2 消息分类
      3.2.1 系统消息 - 由系统定义和使用的消息
         例如:WM_CREATE/WM_SIZE
         消息ID范围为: 0 - 0x03FF(WM_USER-1)
      3.2.2 用户定义消息 - 应用程序可以自己定义和使用的消息, WM_USER(0x0400)
         从WM_USER的ID开始,到0x7FFF,是用户可以定义使用的消息.
      3.2.3 其他消息范围
         WM_APP(0x8000)-0xBFFF:应用程序访问窗口的消息ID
         0xC000-0xFFFF: 应用程序访问消息,使用字符串注册系统产生相应消息ID
      3.2.4 用户定义消息的使用
         1)定义自定义消息ID:

 #define   WM_FIRSTMSG  (WM_USER+1)

2)在窗口处理函数中,响应消息

 switch( nMsg ){case WM_FIRSTMSG://处理函数break;}

3)SendMessage/PostMessage发送消息

    SendMessage( hWnd, WM_FIRSTMSG, 0, 0 );

4 消息队列
    4.1 消息队列 - 用于存储消息的内存空间,消息在队列中是先入先出.
    4.2 消息队列的分类
      4.2.1 系统消息队列 - 由系统维护的消息队列.
      4.2.2 应用程序消息队列(线程消息对列) -属于每个线程的各自拥有的消息队列.
 
  5 消息和消息队列
    5.1 根据消息和消息队列关系,将消息分成两种:
      队列消息 - 可以存放在消息队列中的消息.
      非队列消息 - 发送时不进入消息队列.
    5.2 队列消息
      首先存放到消息队列当中,然后由GetMessage/PeekMessage取出,然后进行处理.
      例如: 鼠标消息/键盘消息/WM_PAINT/WM_QUIT/M_TIMER消息
    5.3 非队列消息
      消息发送直接发送给指定的窗口,查找窗口的处理函数,返回处理结果.
 
 6 消息的获取  
    6.1 消息循环
      6.1.1 GetMesssage从队列中获取消息,判断是否是WM_QUIT消息,如果发现是WM_QUIT消息,消息循环结束,否则继续下一步.
      6.1.2 TranslateMessage 翻译按键消息,如果发现有按键消息,产生字符消息放入消息对列, 继续下一步
      6.1.3 DispatchMessage 找到消息所发窗口的处理函数,处理消息.处理完成后,返回6.1.1.
    6.2 GetMesssage和PeekMessage
      6.2.1 从线程消息队列中获取消息,如果找到消息,就返回消息,进行消息处理. 如果未找到消息,执行6.2.2
      6.2.2 查找系统消息队列.通过向系统消息队列查询,如果找到消息,获取消息并返回,进行消息处理.如果未找到消息,执行6.2.3
      6.2.3 检查窗口需要重新绘制的范围,如果发现存在重新绘制的范围,会产生WM_PAINT消息.然后进行消息处理, 如果未找,执行6.2.4
      6.2.4 检查WM_TIMER定时器消息,如果发现存在已经到时的定时器,会产生WM_TIMER消息.进行消息处理. 如果未找,执行6.2.5
      6.2.5 执行内存管理工作.
      6.2.6 根据函数不同,处理结果不同:
        GetMesssage - 阻塞,等候下一条消息
        PeekMessage - 让出控制权,交给后面的代码执行.
       
  7 消息发送 
    7.1 消息发送分两种
       发送(Send)消息 - 直接发送给指定的窗口,并等候结果.
       投递(Post)消息 - 发送到消息队列当中,立刻返回,由消息循环处理.
    7.2 PostMessage和SendMessage
      PostMessage产生队列消息,由于发送后不等候消息处理结果,所以不能确定消息是否被处理成功.
      SendMessage产生非队列消息,可以确定消息是否成功.

View Code

// winmsg.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "stdio.h"HINSTANCE g_hInst = NULL;
HWND g_hButton = NULL;#define  WM_FIRSTMSG (WM_USER+1)
#define  WM_SECONDMSG (WM_USER+2)LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam);BOOL RegisterWnd(LPSTR pszClassName)
{WNDCLASSEX wce = {0};wce.cbClsExtra = 0;wce.cbSize = sizeof(wce);wce.cbWndExtra = 0;wce.hbrBackground = HBRUSH(COLOR_BTNFACE+1);wce.hCursor = NULL;wce.hIcon = NULL;wce.hIconSm = NULL;wce.hInstance = g_hInst;wce.lpfnWndProc = WndProc;wce.lpszClassName = pszClassName;wce.lpszMenuName = NULL;wce.style = CS_HREDRAW|CS_VREDRAW;ATOM nAtom = RegisterClassEx(&wce);if(0 == nAtom)return FALSE;return TRUE;
}HWND CreateWnd(LPSTR pszClassName)
{HWND hWnd = CreateWindowEx(0, pszClassName,"MyWnd", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,g_hInst,NULL);return hWnd;
}void DisplayWnd(HWND hWnd)
{ShowWindow(hWnd, SW_SHOW);UpdateWindow(hWnd);
}void OnCreate(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{LPCREATESTRUCT pCreateStruct = LPCREATESTRUCT(lParam);//MessageBox(NULL, pCreateStruct->lpszName, "OnCreate", MB_OK);
g_hButton = CreateWindowEx(0, "BUTTON", "Button", WS_CHILD|WS_VISIBLE,0, 0, 100, 100, hWnd, NULL, g_hInst, NULL);SendMessage(hWnd, WM_FIRSTMSG, 0, 0);
}void OnSize(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{int nWidth = LOWORD(lParam);int nHeight = HIWORD(lParam);CHAR szText[256] = {0};sprintf(szText, "WIDTH:%d, HEIGHT:%d", nWidth, nHeight);//MessageBox(NULL, szText, "OnSize", MB_OK);if(NULL != g_hButton){int nX = (nWidth - 100)/2;int nY = (nHeight - 100)/2;MoveWindow(g_hButton, nX, nY, 100, 100, TRUE);}
}BOOL OnSysCommand(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{switch(wParam){case SC_CLOSE:if(IDOK == MessageBox(NULL, "是否将文件存盘?", "提示", MB_OKCANCEL|MB_ICONWARNING)){return TRUE;}return FALSE;}return FALSE;
}LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam)
{switch(nMsg){case WM_CREATE:OnCreate(hWnd, nMsg, wParam, lParam); break;case WM_SIZE:OnSize(hWnd, nMsg, wParam, lParam); break;case WM_SYSCOMMAND:if(FALSE == OnSysCommand(hWnd, nMsg, wParam, lParam))return 0;break;case WM_DESTROY://SendMessage(hWnd, WM_QUIT, 0, 0);PostMessage(hWnd, WM_QUIT, 0, 0);//PostQuitMessage(0);return 0;case WM_FIRSTMSG:MessageBox(NULL, "FirstMGS", "FIRSTMSG", MB_OK); break;}return DefWindowProc(hWnd, nMsg, wParam, lParam);
}void Message()
{MSG msg = {0};while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}
}int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR     lpCmdLine,int       nCmdShow)
{g_hInst = hInstance;RegisterWnd("MyWnd");HWND hWnd = CreateWnd("MyWnd");DisplayWnd(hWnd);Message();return 0;
}

二 WM_PAINT消息

1 WM_PAINT的产生
   由于窗口的互相覆盖等,产生需要绘制的区域,那么会产生WM_PAINT消息.
   一般情况下,不直接发送WM_PAINT消息,通过API声明需要绘制区域,来产生WM_PAINT消息.
   例如,可以使用InvalidateRect声明一个需要重新绘制的区域.
 
  2 WM_PAINT的注意点
    2.1 如果一个消息队列中,有多个WM_PAINT消息,只有最后一个WM_PAINT消息会被处理.
    2.2 WM_PAINT消息处理中,要清空需要被绘制的区域. BeginPaint
     
  3 WM_PAINT的使用
    3.1 WM_PAINT开始时,必须调用BeginPaint
    3.2 绘制图形
    3.3 WM_PAINT处理后,必须调用EndPaint

View Code

// winpaint.cpp : Defines the entry point for the application.
//

#include "stdafx.h"HINSTANCE g_hInst = NULL;void OnPaint(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps = {0};HDC hDC = BeginPaint(hWnd, &ps);CHAR szText[] = "Hello WM_PAINT";TextOut(hDC, 100, 100, szText, strlen(szText));Rectangle(hDC, 200, 200, 300, 300);
}LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{switch(nMsg){case WM_PAINT:OnPaint(hWnd, nMsg, wParam, lParam); break;case WM_DESTROY:PostQuitMessage(0); return 0;}return DefWindowProc(hWnd, nMsg, wParam, lParam);
}BOOL RegisterWnd(LPSTR lpszClassName)
{WNDCLASSEX wce = {0};wce.cbClsExtra = 0;wce.cbSize = sizeof(wce);wce.cbWndExtra = 0;wce.hbrBackground = HBRUSH(COLOR_BTNFACE + 1);wce.hCursor = NULL;wce.hIcon = NULL;wce.hIconSm = NULL;wce.hInstance = g_hInst;wce.lpfnWndProc = WndProc;wce.lpszClassName = lpszClassName;wce.lpszMenuName = NULL;wce.style = CS_HREDRAW|CS_VREDRAW;ATOM nAtom = RegisterClassEx(&wce);if(0 == nAtom){return FALSE;}return TRUE;
}HWND CreateWnd(LPSTR lpszClassName)
{HWND hWnd = CreateWindowEx(0,lpszClassName, "MyWnd", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, g_hInst, NULL);return hWnd;
}void DisplayWnd(HWND hWnd)
{ShowWindow(hWnd, SW_SHOW);UpdateWindow(hWnd);
}void Message()
{MSG msg = {0};while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}
}int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR     lpCmdLine,int       nCmdShow)
{g_hInst = hInstance;RegisterWnd("MyWnd");HWND hWnd = CreateWnd("MyWnd");DisplayWnd(hWnd);Message();return 0;
}

三 键盘消息

1 键盘消息
   按键消息
     WM_KEYDOWN 当键被按下时产生
     WM_KEYUP 当键被释放时产生
     WM_SYSKEYDOWN 当系统键被按下时产生 ALT/F10
     WM_SYSKEYUP 当系统键释放时产生
    字符消息
     WM_CHAR 当有字符键被按下时产生
      TranslateMessage会将WM_KEYDOWN消息中,可以显示的按键,转换成WM_CHAR的消息
  2 消息参数
    WPARAM - 虚拟键码
    LPARAM - 相关的按键信息.
 
  3 消息的使用
    3.1 当有按键消息时,首先进入系统消息队列,然后被程序的消息循环获取.
    3.2 消息的处理
  4 键盘消息的顺序
    对于可显示字符: WM_KEYDOWN,WM_CHAR,WM_KEYUP
    对于不可显示字符: WM_KEYDOWN,WM_KEYUP
    对于系统键:WM_SYSKEYDOWN,WM_SYSKEYUP
    如果按键一直不释放,会重复产生
         WM_KEYDOWN(WM_CHAR)

View Code

// winkeboard.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "stdio.h"HINSTANCE g_hInst = NULL;
HANDLE g_hStdOut = NULL;LRESULT CALLBACK WinProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{switch(nMsg){case WM_KEYDOWN:{CHAR szText[] = "WM_KEYDOWN\n";switch(wParam){case VK_LEFT:case VK_RIGHT:case VK_UP:case VK_DOWN:WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL);break;}}break;case WM_KEYUP:{CHAR szText[] = "WM_KEYUP\n";WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL); break;}break;case WM_SYSKEYDOWN:{CHAR szText[] = "WM_SYSKEYDOWN\n";WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL); break;}break;case WM_SYSKEYUP:{CHAR szText[] = "WM_SYSKEYUP\n";WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL); break;}break; case WM_CHAR:{CHAR szText[260] = {0};sprintf(szText, "WM_CHAR: %c\n", wParam);WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL); break;}break;case WM_DESTROY:PostQuitMessage(0); return 0;}return DefWindowProc(hWnd, nMsg, wParam, lParam);
}BOOL ResiterWnd(LPSTR lpszClassName)
{WNDCLASSEX wce = {0};wce.cbClsExtra = 0;wce.cbSize = sizeof(wce);wce.cbWndExtra = 0;wce.hbrBackground = HBRUSH(COLOR_BTNFACE+1);wce.hCursor = NULL;wce.hIcon = NULL;wce.hIconSm = NULL;wce.hInstance = g_hInst;wce.lpfnWndProc = WinProc;wce.lpszClassName = lpszClassName;wce.lpszMenuName = NULL;wce.style = CS_HREDRAW|CS_VREDRAW;ATOM nAtom = RegisterClassEx(&wce);if(0==nAtom){return FALSE;}return TRUE;
}HWND CreateWnd(LPSTR lpszClassName)
{HWND hWnd = CreateWindowEx(0, lpszClassName, "MyWnd",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,NULL, NULL, g_hInst, NULL);return hWnd;
}void ShowWnd(HWND hWnd)
{ShowWindow(hWnd, SW_SHOW);UpdateWindow(hWnd);
}void Message()
{MSG msg = {0};while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}
}void NewConsole()
{AllocConsole();g_hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);CHAR szText[] = "Debug Message......:\n";WriteConsole(g_hStdOut, szText, strlen(szText), NULL, NULL);
}int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR     lpCmdLine,int       nCmdShow)
{NewConsole();g_hInst = hInstance;ResiterWnd("MyWnd");HWND hWnd = CreateWnd("MyWnd");ShowWnd(hWnd);Message();return 0;
}      

转载于:https://www.cnblogs.com/tangzhengyue/archive/2012/08/12/2634295.html

Win32编程day04 学习笔记相关推荐

  1. 《Linux高性能服务器编程》学习笔记

    <Linux高性能服务器编程>学习笔记 Linux高性能服务器编程 TCP/IP协议族 TCP/IP协议族体系结构以及主要协议 数据链路层 网络层 传输层 应用层 封装 分用 测试网络 A ...

  2. Java编程思想学习笔记-第11章

    <?xml version="1.0" encoding="utf-8"?> Java编程思想学习笔记-第11章 Java编程思想学习笔记-第11章 ...

  3. 【C#编程基础学习笔记】6---变量的命名

    2013/7/24 技术qq交流群:JavaDream:251572072  教程下载,在线交流:创梦IT社区:www.credream.com [C#编程基础学习笔记]6---变量的命名 ----- ...

  4. 【C#编程基础学习笔记】4---Convert类型转换

    2013/7/24 技术qq交流群:JavaDream:251572072  教程下载,在线交流:创梦IT社区:www.credream.com [C#编程基础学习笔记]4---Convert类型转换 ...

  5. 《基于GPU加速的计算机视觉编程》学习笔记

    <基于GPU加速的计算机视觉编程>学习笔记(1) 最近打算 准备工作 CUDA开发环境(主要是查看N卡的信息) 在WIN10下安装CUDA工具包 最近打算 在训练模型的时候,感觉电脑非常吃 ...

  6. Linux C编程一站式学习笔记2

    Linux C编程一站式学习笔记 chap2 常量.变量和表达式 本书以C99为标准 一.继续hello world 加入更多注释的hello world 可以用ctrl+(shift)+v复制到vi ...

  7. 熊猫的python小课_朋友圈里那个可爱的小熊猫Python编程的学习笔记,学编程,不难!...

    Print( ) 详细请见公众号文章,里面有让人印象深刻,无法忘记的灵魂画手的图画解释.朋友圈里那个可爱的小熊猫Python编程的学习笔记,学编程,不难!​mp.weixin.qq.com 人类有人类 ...

  8. GO 编程模式学习笔记——GO GENERATION

    GO编程模式学习笔记系列为学习陈皓的GO编程模式系列文章记录与心得. 原文链接:GO 编程模式:GO GENERATION Go语言代码生成主要还是用来解决编程泛型的问题.Go语言的类型检查有两种技术 ...

  9. 编程开发学习笔记之程序员如何用1年时间获得3年成长(图)

    2019独角兽企业重金招聘Python工程师标准>>> 编程开发学习笔记之程序员如何用1年时间获得3年成长(图) 前言 这世界存在这么一个银行,你一出生,就自动享有这家银行为你开设的 ...

最新文章

  1. redis主从复制、高可用和集群
  2. Python 2.7 将于7个月后终结,这是你需要了解的3.X炫酷新特性
  3. PetShop之ASP.NET缓存(转载)
  4. 修改mysql用户家目录,Linux 更改MySQL目录
  5. php打印预览jquery,JS实现浏览器打印、打印预览示例
  6. SpringMVCDemo中,遇到的问题(一)
  7. (二十)ArcGIS JS 加载WMTS服务(超图示例)
  8. mysqltimestamp默认值
  9. Atitit 微信小程序的部署流程文档 目录 1.1. 设置https 参照 Atitit tomcat linux 常用命令 1 1.2. 增加证书 腾讯云和阿里云都可申请免费证书,但要一天
  10. 计算机及网络信息安全管理制度,计算机、网络管理及信息安全管理制度
  11. 【毕业季·进击的技术er】大学生计算机毕业设计应该这样写
  12. Vue - Todos 案例
  13. 分享ASP.NET视频系列教程——第十九讲 ASP.NET内置的AJAX
  14. IE打开网页默认为英文
  15. 分库分表之MyCat应用
  16. 【翠花学Vue】每日打卡——vue打卡6
  17. windows磁盘管理压缩卷只能压缩一部分的问题解决办法
  18. 现金的消亡与货币的未来之战 |链捕手
  19. idea怎样创建jsp文件
  20. A002-185-2521-李子泓

热门文章

  1. How to Make a Computer Operating System
  2. linux 进程 ctrl-c,ctrl-z,ctrl-d
  3. 关于百度分享——bdCustomStyle一点bug
  4. 不好意思,食言而肥了
  5. 《LeetCode力扣练习》剑指 Offer 30. 包含min函数的栈 Java
  6. winform中构造函数与Form_Load
  7. 微型计算机2013年10月下,微型计算机及接口技术2013年10月真题试题(04732)
  8. redis mysql主从同步_手撕Redis,主从同步
  9. java 滚轮页面缩放_急..JAVA 在画布上画拖动滚动条可扩大缩小的长方形
  10. everything文件搜索_本地文件搜索神器,Everything、Listary、AnyTXT Searcher!