zoukankan      html  css  js  c++  java
  • WINDOWS窗口消息

    Windows窗口消息

     

    不看不知道,一看吓一跳。原来就只是单单理解了SendMessagePostMessage。前者是发送完要处理后再返回,后者是发送后立即返回,不管有没有处理。但今天仔细看了书上讲解后,才发现原来事情多着呢。

     

    窗口对象:线程里会有两种特别的对象,即窗口对象和挂钩对象。要知道,进程是分配资源的单位,因此,如果我们创建了某些资源,当我们没有明确要求释放的时候,这些资源只有在进程退出时才被释放。 但窗口对象和挂钩对象不同,他们是属于创建他们的线程的。原因是,窗口和挂钩对象的消除需要依靠WM_DESROYWM_NCDESTROY消息,而如果线程退出了,消息循环不再继续,窗口收不到销毁信息,自然是释放不掉了。因此,如果一个线程创建了一个窗口或是安装了一个挂钩,线程结束后,操作系统会自动删除窗口或卸载挂钩。

     

    首先来看看,消息的拥有者,消息队列。

    THREADINFO: 

    每个创建窗口的线程,系统都会为之分配一个THREADINFO结构的实例。这个结构如下

     

    Struct THREADINFO

    {

     PostMessageQueue;  登记消息队列

     VirtualInputMessageQueue; 虚拟输入队列

     SendMessageQueue; 发送消息队列

     ResultMessageQueue; 应答消息队列

     nExitCode; 退出码

     bActive; 唤醒标志

     LocalInputStateValue; 局部输入状态变量

    }

     

    当线程有了THREADINFO后,这个线程就有了自己的消息队列集合。这是每个线程专有的,有多少个线程创建了窗口,就有多少个这样的集合。

     PostMessage:

    先看看UBOOL PostMessage( HWND hwnd,UINT msg,WPARAM,LPARAM);

    当一个线程调用这个函数时,系统要确定是哪一个线程建立了用hwnd参数标识的窗口。然后系统分配一块内存,将这个消息参数存在这块内存中。并将这块内存增加到相应线程的登记消息队列中(Post)。并且,这个函数还设置QS_POSTMESSAGE唤醒位,这个位.然后就返回.调用这个函数的线程并不知道这个消息有没有被处理.

     也可以通过UBOOL PostThreadMessage( DWORD dwThreadId,UINT msg,WPARAM,LPARAM);函数将消息直接放置在线程的消息队列中.通常选择HWNDTHREADID中较方便的一个. 这个函数和上一个一样,发出消息后立即返回.

    向线程发送消息的还有VOID PostQuitMessage(int nExitCode);也可以调用PostThreadMessage(GetCurrentThreadId(),NULL,WM_QUIT,nExitCode,0);来完成这个功能.值得注意的是, PostQuitMessage并不会将消息放入线程的消息队列.只是在内部PostQuitMessage设置QS_QUIT唤醒标志.并设置THREADINFO结构的nExitCode成员.

     SendMessage

    下面来看看SendMessage函数.它与PostMessage有着同样的参数.但是,当一个线程发送一个消息的时候,窗口过程将处理这个消息.只有当消息被处理后.SendMessage函数才返回.

     

    SendMessage发送消息给调用线程和发送消息到另外一个线程的情况是不一样的. 当发送给自己的时候,SendMessage做了类似如下的工作.

    SendMessage(NULL,nMsg,wParam,lParam)

    {

       Return  MsgProc(NULL,nMsg,wParam,lParam);

    }

     

    可以看出,SendMessage只是简单地调用了自己的窗口处理函数,然后待处理完成之后,便返回.但是,当一个线程向其它线程发送消息的时候,情况就复杂多了. 为了保证这个SendMessage函数是要在被处理后再返回,那么就需要线程间的同步.下面将展现了将要做的事.

    1 系统将发送的消息追加到接受线程的消息队列.同时为这个线程设置QS_SENDMESSAGE标志

    2 如果接收线程并没有在等待消息(即不是处于GetMessage,PeekMessage,WaitMessage)的时候,发送的消息不会处理.但是,系统不能中断线程来处理这个消息. 如果接收线程是在等待消息.那么系统首先检测QS_SENDMESSAGE标志,如果是,系统便扫瞄消息列表,并找到第一个消息. 注意,系统只会依次处理他消息队列中的消息. 这个来自于其它线程的消息并不会得到优待.

     

    3 当接收线程在处理消息的时候,发送线程将挂起.并被设置为空闲状态,这表示他在等待他的应答队列中出现消息.当接收线程处理完该消息后.会向发送线程的应答消息队列中发送一个消息,以告知消息处理完成. 当一个线程在等待消息时,它几乎是处于空闲状态.但是它可以执行一个任务.就是如果系统中另外一个线程向这个发送线程发送消息的时候.则它要立即处理这个来自于其它线程的消息.在这种情况下,系统不必等待线程去调用GetMessage,PeekMessage,WaitMessage);

     

     SendNotifyMessage

    还有一个SendNotifyMessage函数.这个函数发送一个消息后便立即返回. PostMessage不同的是,它发送的消息是加入到发送消息队列中的. 而由于系统处理发送消息队列的优先级比登记(post)消息要高. 并且,当一个线程调用这个函数来向自己发送消息时,它的作用和SendMessage一样.

     

     

     

     

  • 相关阅读:
    收集珠子
    压缩变换(程序设计)
    动态规划-树上dp-1757. 搜集钻石
    动态规划-1620. 收集硬币
    动态规划-状态压缩-707. 最优账户结余
    图-1400. 图的费马点
    数学-快速幂
    计算几何-5361. 圆和矩形是否有重叠
    图-搜索-dfs-739. 24点
    图-dfs-连通分量-旋转变换-804. 不同岛屿的数量II
  • 原文地址:https://www.cnblogs.com/qilinzi/p/1940481.html
Copyright © 2011-2022 走看看