Chinaunix首页 | 论坛 | 博客
  • 博客访问: 330966
  • 博文数量: 73
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1293
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-07 11:17
个人简介

爱运动,爱看书,爱生活!

文章分类

全部博文(73)

文章存档

2014年(7)

2013年(66)

分类: WINDOWS

2013-06-06 13:15:33

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


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


BOOLGetMessage(
  LPMSGlpMsg, //存放获取到的消息数据
  HWNDhWnd, //获取窗口的额消息句柄
  UINTwMsgFilterMin, //消息过来的起始消息
  UINTwMsgFilterMax); //消息过滤的终止消息


返回值BOOL:成功获取消息,返回TRUE ,当获取到WM_QUIT消息时,退出消息


可以使用PostQuitMessage向窗口发送WM_QUIT消息


MSG :由系统填写关于消息的参数


Hwnd:GetMessage会根据hWnd的值,接收由hWnd指定窗口的消息


wMsgFilterMin, wMsgFilterMax:消息过滤器要求GetMessage接收指定范围内的消息


               2.3.2eTransplateMessage:将键盘消息转换为字符消息
                         1.首先检查是否是键盘消息
                         2.如果发现时键盘消息,将会根据按键产生一个字符的消息,
                           在下一个GetMessage执行时,会收到这个消息
                         3.如果未发现按键消息,不做任何处理
               2.3.3DispatchMessag
                    根据消息数据类的窗口句柄,找到这个窗口的处理函数,调用处理函数,进行消息处理
               如果MSG中,HWND窗口句柄为空,DispatchMessage不做任何处理
          2.4Win32基本消息
                    2.4.1 WM_DESTROY 窗口销毁时的消息,可以做退出或善后处理
                    2.4.2 WM_CREATE 窗口创建后
                              窗口处理函数收到的第一条消息
                              可以在这个消息内部做数据初始化/创建子窗口   WPARAM wParam 不使用
                              LPARAM lParam  LPCREATESTRUCT的指针要转化
                    2.4.3 WM_SIZE
                         当窗口大小发生变化时,会收到这个消息
                         可以在这个消息中调整窗口布局。
                         wParam - SIZE 发生变化时的标识;
                              int nWidth=LOWORD(lParam);//屏幕X坐标
                              int nHight=LOWORD(lParam);//屏幕Y坐标
                   2.4.4 WM_SYSCOMMAND
                         系统命令消息,当点击系统菜单时会收到这儿消息
                         可以在这个消息中,提示用户保存数据
                    2.4.5WM_PAINT绘图消息
                    2.4.6键盘消息
                    2.4.7 鼠标消息
                    2.4.8 WM_TIMER定时器消息
          2.5MSG -消息结构


typedefstructtagMSG{
  HWNDhwnd; //消息窗口句柄
  UINTmessage; //消息标示
  WPARAMwParam; //消息参数32位
  LPARAMlParam; //
  DWORDtime; //消息产生的时间
  POINTpt;//消息产生时鼠标的位置
}MSG;


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


LRESULTSendMessage(
  HWNDhWnd, 消息窗口
  UINTMsg, 消息ID
  WPARAMwParam, 消息参数
  LPARAMlParam); 消息参数
}MSG;


3消息的组成和分类
     3.1 消息的组成
          窗口句柄/消息ID/消息参数(WPARAM高32位,LPARAM低32)
     3.2 消息分类
          3.2.1 系统消息:由系统定义和使用的消息
                  列如:WM_CREATE/WM_SIZE
                    消息ID范围为:0-0x3FF(WM_user-1)
          3.2.2 用户定义的消息-应用程序可以自己定义和使用的消息,WM_USER(0x0400)
          从WM_USER的ID开始,到0x7FFF,是用户可以自定义使用的消息


          3.2.3 用户定义的消息的使用
          1)定义自定义的消息Id
          WM_APP(0x8000) - 0xBFFF :应用程序访问窗口的消息Id
          0xC000 - 0xFFFF:应用程序访问消息,使用字符串注册系统产生相应消息ID
#define WM_FIRSTMSG (WM_USER+1)
#define WM_FIRSTMSG (WM_USER+2)
          2)在窗口处理函数中响应消息
     case WM_FIRSTMSG:
          MessageBox(NULL,"FIRSTMSG","MSG",MB_OK);
          break;
          3)SendMessage/PostMessage
SendMessage(hWnd,WM_FIRSTMSG,0,0);


       4.消息队列
              4.1 消息队列 用户存储消息的内存空间
                  消息在队列是先入先出。
              4.2 消息队列的分类
                  4.2.1 系统消息队列-由系统维护的消息队列
                  4.2.1 应用程序消息队列(线程消息队列)-属于每个线程的各自拥有的消息队列
          5.消息和消息队列
               5.1根据消息和消息队列关系,将消息分为两种
                    队列消息-可以存放在消息队列中的消息
                    非队列消息-发送时不进入消息队列
               5.2 队列消息
                    首先存放到消息队列当中,然后由GetMessage或PeekMessage取出,进行处理,
                    列如:鼠标消息,键盘消息/WM_PAINT/WM_QUIT /WM_TIMER消息
               Postmessage
               5.3 非队列消息
                         消息发送之后,不进入队列,直接发送给指定的窗口,查找窗口的处理函数,返回处理结果
                    非队列消息的产生来自于SendMessage
          6.消息的获取
               6.1 消息循环
             6.1.1  GetMessage 获取消息,判断是否是WM_QUIT消息,如果发现是WM_QUIT,消息循环结束,否则继续下一步
              6.1.2 TranslateMessage 翻译按键消息,如果发现有按键消息,产生字符消息放入消息队列,继续下一步


              6.1.3 DisapatchMessage 找到消息所发窗口的处理函数,处理消息,处理完成后,返回6.1.1


              6.2 GetMessage和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 根据函数不同,处理结果不同
               GetMessage 阻塞,等候下一消息
               PeekMessage 让出控制权,交给后面的代码执行


     7消息发送
               7.1 消息发送分两种
                    发送(send)消息 -直接发送给指定窗口,并等候结果
                    投递(Post)消息 -发送到消息队列中,立刻返回,由消息循环处理
                    7.2 Postmessage 和SendMessage
                    Postmessage 产生队列消息,由于发送后不等候消息处理结果,所以不能确定消息是否被处理成功
                    SendMessage 产生非队列消息,可以确定消息是否成功


二、 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消息处理中,要清空需要被绘制的区域
3.WM_PAINT的使用
          3.1 WM_PAINT开始时,必须调用BeginPaint
          3.2 绘制图形
          3.3 WM_PAINT 处理后,必须EndPaint


三 键盘消息
          1.键盘消息
               WM_KEYDOWN 当键被按下时产生
               WM_KEYUP 当键被释放时产生
               WM_SYSKEYDOWN   ALT/F10 当系统键被按下时产生
               WM_SYSKEYUP  当系统键被释放时产生
               字符消息
               WM_CHAR  当字符键被按下时产生
               TranslateMessage会将WM_KEYDOWN消息中,可以显示的按键,转换成WM_CAHR的消息


               2 消息参数
                    WPARAM -虚拟键码
                    LPARAM - 相关按键信息
               3. 消息的使用
                    3.1 当有按键消息时,首先进入系统消息队列,然后被程序的消息循环获取
                    3.2 消息的处理
                         对于可显示的字符:WM_CHAR WM_KEYDOWN,WM_KEYUP
                         对于不可显示的字符:WM_KEYDOWN,WM_KEYUP
                         对于系统键:WS_SYSKEYDOWN ,WS_SYSKEYUP
                         如果按键一直不释放,会重复产生
                         WM_KEYDOWN(WM_CHAR)


 一、鼠标消息
     1 鼠标消息
          1)基本鼠标消息
          WM_LBUTTONWN 左键按下
          WM_LBUTTONUP  左键抬起
          WM_RBUTTONDOWN 右键按下
          WM_RBUTTONUP 右键抬起
          WM_MOUSEMOVE 鼠标移动
          2)双击消息
          WM_LBUTTONDBCLK 左键双击
          WM_RBUTTONDBCLK 右键双击
          3)滚轮消息
          WM_MOUSEWHEEL 鼠标滚轮


2 消息的参数
     WPARAM - 当前键盘按键状态,列如MB_CONTROL/MK_SHIFT,MB_LBUTTON
     LPARAM 当前鼠标的坐标,坐标的原点是窗口
     X坐标 LOWORD(lParam),低16位
     Y坐标 HIWORD(lParam) ,高16 位


参数具体内容和具体鼠标消息有稍微不同
     2 消息的使用
          3.1 基本鼠标消息,只需在窗口处理函数增加消息处理即可,当消息来临,获取鼠标状态
case WM_MOUSEMOVE:
          {
               int nX=LOWORD(lParam);
               int nY=HIWORD(lParam);
             }


附:坐标转换函数 CLientToScreen,可以将鼠标坐标转换为屏幕坐标


3.2 双击消息
     3.2.1 窗口注册要增加CS_DBCLICKS 类型
          wce.style=CS_DBCLICKS|...
     3.2.2在窗口处理函数中增加消息处理
     3.2.3产生过程,列如:WM_LBUTTONDBLCLK..............
连续两次WM_LBUTTONDBLCLK时间不超过预定的时间间隔,就会产生LUBUTTONDBCLICK消息
双击时间可以通过控制面板调整


     3.3滚轮消息
3.3.1 由于WM_MOUSEWHEEL需要在Winnet4.0以上的版本支持,所以需要包含在windows.h 的头文件前,增加_WIN32_WINNT 宏定义
          #define _WIN32_WINNT 0x0400
3.3.2 在窗口处理函数中增加消息处理
3.3.3 参数
     LPARAM 与其他鼠标消息类同
WPARAM -LOWORD(WPARAM) 表示按键状态
                                                              滚轮滚动幅度,120 的倍数


 二、定时器消息


1.定时器消息 WM_TIMER
     按照定时器设置时间段,自动向窗口发送一个定时器消息WM_TIMER。优先级比较低
     精度比较低,毫秒级别,产生时间精度比较低。
2 消息和函数
     WM_TIMER  消息ID
          wParam :定时器ID
          lParam: 定时器处理函数
          SetTimer  设置一个定时器


UINT SetTimer(  HWND hWnd, //窗口句柄,可以为NULL


  UINT nIDEvent,   //定时器的Id,0为不预设ID号


UINT uElapse, //定时器的时间间隔,毫秒级别


TIMERPROC lpTimerFunc ); //定时器处理函数,也可以为空


    返回一个创建好的定时器ID


          KillTimer    结束一个定时器


BOOL KillTimer(  HWND hWnd, //窗口句柄


UINT uIDEvent ); //定时器ID


          TimerProc   定时器处理函数


void CALLBACK TimerProc(  HWND hwnd,//窗口句柄


  UINT uMsg, //WM_TIMER 消息ID


UINT idEvent, //定时器ID


DWORD dwTime ); //当前系统时间


3. 使用方式
     3.1 创建定时器
          3.1.1 指定窗口句柄HWND,那么TIMERPROC参数可以为空,
            那么WM_TIMER消息将会发送给指定窗口,如果未指定TIMERPROC不能为空,必须指定定时器出路程序
          3.1.2 如果指定定时器ID,SetTimer会按照这个ID创建定时器,如果未指定,会返回一个创建定时器ID
     3.2 处理消息
可以根据消息传入定时器ID号分别处理
     3.3 结束定时器
     在不使用时,KillTimer(hWnd,1000)结束定时器
  三、 菜单
     1、菜单基础
菜单创建后,会返回HMENU句柄
菜单项-每个菜单项会有一个ID号,可以根据这个ID执行不同的操作
     2.菜单的使用
          2.1 菜单的创建
          CREATEMENU-     MENU 菜单
           CREATEPOPUPMENU-         POPUPMENU 弹出式菜单
            AppenedMenu -增加菜单项
          BOOLAppendMenu(


  HMENU hMenu, //菜单句柄
  UINT uFlags, //菜单项标示
  UINT uIDNewItem, //菜单项的ID或子菜单的句柄
  LPCTSTR lpNewItem ); //菜单项的名称


UINT uFlags:


    MF_STRING -lpNewItem 是一个字符串


    MF_POPUP -uIDNEWItem 是一个子菜单句柄


    MF_SEPARATOR -增加分隔栏


    MF_CHECKED/MF_UNCHECKED 菜单项小对勾的设置和取消


    MF_DISABLED/MF_ENABLE 菜单项禁止和允许状态


2.2 菜单的命令响应


    2.2.1 WM_COMMAND消息


    当用户点击菜单或按钮控件等,系统会向窗口发送WM_COMMAND消息


    WPARAM: HIWORD- 通知消息标识


                LOWORD -菜单项的ID号


    LPARAM:控件的句柄


    2.2.2 命令处理


        根据菜单项的ID号做相应的处理


    2.3 菜单项的状态


        2.3.1 WM_INITMENUPOPUP消息


            当用户点击菜单,显示弹出菜单之前,系统会向窗口发送WM_INITMENUPOPUP消息


            WPARAM:是菜单句柄


            LPARAM:LOWORD -菜单位置


                    HIWORLD-是否是系统菜单


       2.3.2 命令处理
               根据WPARAM的菜单句柄,使用MenuAPI函数,修改菜单状态。
               CheckMenuItem - 选择
               EnableMenuItem -允许和禁止
               SetMenuInfo-  设置更多信息


一系统菜单
     1 执行系统提供的窗口命令,列如最大化、关闭、等命令,本质上和普通菜单一样,所以我们也可以在程序中使用这个菜单
2 系统菜单的使用
     2.1 获取系统菜单
          HMENU GetSystemMenu(


  HWND hWnd,  //要获取的窗口句柄
  BOOL bRevert );//获取时重置标示
bRevert: TRUE 重置 FALSE 不重置
当Revert为TRUE时,会将菜单重新置成默认状态,并返回菜单句柄,如果为FALSE,菜单项不重置,获取到当前系统的菜单状态


     2.2 修改系统菜单,列如增加、删除
          AppendMenu
          InsertMenu 比AppendMenu增加了一个插入菜单项的位置或ID
          RemoveMenu


BOOL RemoveMenu(
  HMENU hMenu,//菜单句柄
  UINT uPosition, //菜单项的位置或ID
  UINT uFlags );//菜单项的位置或ID的标示


     2.3 系统菜单的命令响应
          系统菜单的命令响应,是在 WM_SYSCOMMAND中
WPARAM-LOWORD(wParam) 增加菜单的ID
switch(nID)
     {
     case 1001:
          MessageBox(NULL,"Hello 1001","SysMenu",MB_OK);
          break;
     case 1002:
          MessageBox(NULL,"Hello 1002","SysMenu",MB_OK);
          break;
}
二、右键菜单
     1.右键菜单
          当在窗口点击鼠标右键时,弹出时的菜单
     2.右键菜单的使用
          2.1创建菜单
               CreatePopMenu
          2.2菜单的增加
               AppendMenu
          2.3菜单的显示
               TrackPopupMenu


BOOL TrackPopupMenu(
  HMENU hMenu, //显示的菜单句柄
  UINT uFlags, //显示的方式
  int x, //菜单的X屏幕坐标
  int y, //菜单的Y屏幕坐标
  int nReserved, //保留,必须为0
  HWND hWnd, //处理菜单命令的窗口句柄
  const RECT* prcRect );//忽略


          2.4菜单的命令处理
               WM_COMMAND
          2.5 使用菜单的位置
              2.5.1 WM_RBUTTONUP
                  WM_RBUTTONUP中,添加菜单的创建及显示,
                    右键消息坐标,转换成屏幕坐标使用。
                         ClientToScreen
               2.5.2 WM_CONTEXTMENU消息
                    用于显示右键菜单的消息。
                    WPARAM -右键点击时对应窗口的句柄
                    LPARAM - 右键抬起时鼠标的屏幕坐标位置
                    LOWORD(lparam) -X屏幕坐标
                    HIWORD (lparam)   -Y屏幕坐标
         2.5.3WM_RBUTTONUP和WM_CONTEXTMENU对比
               1)坐标系不同,RUTTONUP客户区坐标
                         CONTEXTMENU屏幕坐标
               2)先有WM_RBUTTONMENU消息,后又WM_CONTEXTMENU
     三、资源的使用
     1资源文件
          图标、光标、字符串、菜单、加速件、位图资源、对话框资源等等
     资源脚本文件 - *.rc扩展名为RC文件,定义了资源和相关文件等信息
     资源编译器- RC.exe
     2图标资源ICON
         2.1 常用的几种ICON大小:16X16,32X32,48X48
         2.2 使用
               LoadIcon


HICON LoadIcon(
  HINSTANCE hInstance,  //应用程序句柄
  LPCTSTR lpIconName); //图标的ID字符串


2.3 系统提供的图标


    hInstance 为空,lpIconName为定义的系统图标


2.4 自己绘制的图标


    hInstance为图标所在的应用程序的实例句柄


2.5 一个图标文件中,可以包含多种大小、颜色不同的图标,系统使用图标时候


通过大小拉匹配,如果未找到大小完全一致的,那么会使用大小最接近的图标格式替换


3  光标资源


    3.1 光标资源


               热点(光标产生鼠标点击的位置) -Hotspot   -16*16光标
          3.2 使用
               HCURSOR LoadCursor (HINSTANCE 应用程序实例句柄,LPSTR 光标ID);
          3.3 系统的光标
               hInstance为空,lpCursorName 指定为系统的光标即可获得
          3.4 自己绘制的光标
                    hInstance不能为空
          3.5 WM_SETCURSOR
                    当鼠标在窗口内就会产生,可以在程序运行的过程中修改鼠标的样式
               wParam 窗口句柄
               LOWORD(lParam) 所在位置的标识
               HIWORD(lparam) 鼠标消息ID
               SetCursor 设置当前窗口的光标
     4.字符串资源
          4.1 包含字符串的资源
          4.2 使用
                    LoadString


int LoadString(
  HINSTANCE hInstance, //程序句柄
  UINT uID, //字符串资源的ID
  LPTSTR lpBuffer, //存放字符串的Buffer
  int cchBufferMax ); //BUFF 大小


返回字符串的长度


5 菜单资源


    5.1添加菜单资源


    5.2 加载菜单资源


        LOadMenu


HMENU LoadMenu(
  HINSTANCE hInstance, //应用程序句柄
  LPCTSTR lpMenuName );//菜单ID字符串
返回加载成功的菜单句柄
     5.3 命令处理
          使用添加的菜单ID的宏,在WM_COMMAND消息中,处理菜单命令
    6.加速键资源
        6.1 加速键的作用
               可以使用加速键执行命令。列如ctrl+s存盘
        6.2 加速键资源的添加
        6.3 加速键的使用
              6.3.1 加载
   HACCELLoadAccelerators(


  HINSTANCE hInstance, //加速键所在的应用程序句柄
  LPCTSTR lpTableName ); //加速键表的ID字符串
     加载成功返回加速键表的句柄


            6.3.2 增加消息处理


                int TranslateAccelerator(


  HWND hWnd, //处理加速键的窗口句柄
  HACCEL hAccTable, //加速键表
  LPMSG lpMsg );//MSG结构的地址


     6.4 关于加速键的消息
          TranslateAccelerator 将WM_KEYDOWN或者WM_SYSKEYDOWN消息,翻译成WM_COMMAND或者WM_SYSCOMMAND消息
          当收到KEYDOWN或者SYSKEYDOWN消息时,会根据加速键表中按键和命令ID的对应关系,找到相应的命令ID,然后调用窗口的处理函数,
          执行WM_COMMAND消息或者WM_SYSCOMMAND消息
     当找到对应的命令ID并执行后,Translatraccelerate 返回非零,那么就不再执行后续的处理,消息循环等候下一条消息,否则,继续让消息循环中的TranslateMessage和DIspatchMessage处理

阅读(3285) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~