消息处理(二):投递与发送

      消息的投递(Post)过程类似于普通信件的投递过程。普通信件通过邮递员到达收信方的信箱里,收信方取得该信,阅读信件内容,并可能回信。在这个过程中,邮递员的责任只是将信件送到收信者的信箱,一切任务就完成了。

      消息的发送(Send)过程理解为打电话交流的过程。甲找到乙的电话号码,然后开始拨号。如果运气好,拨通了乙的电话,那么两人就联系上了。假设甲方从不主动挂断电话,那么只有乙方先挂断电话,两人的一次联系才宣告结束。

PostMessage函数

BOOL PostMessage(
     HWND        hWnd,                  //目标窗口句柄
    UINT          Msg,                    //消息
    WPARAM     wParam,              //第一个消息参数
    LPARAM      lParam                //第二个消息参数
);

CWnd::PostMessage提供了对PostMessage的简单包装,他首先断言窗口句柄表示一个窗口,然后以窗口句柄为第一个参数调用全局的PostMessage:

_AFXWIN_INLINE BOOL CWnd::PostMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
   ASSERT(::IsWindow(m_hWnd));
   return ::PostMessage(m_hWnd, message, wParam, lParam);
}

hWnd有两个特殊的值:HWND_BROADCAST和NULL。前者表示要将该消息投递到系统当前所有的非子窗口。后者表示由线程而不是某个窗口的窗口过程来处理该消息。
Msg表示投递的消息标志,最后两个参数则表示特定于该消息的参数。千万要注意,因为投递消息类似于异步调用,所以在消息参数中传递指针是非常危险。

SendMessage函数

LRESULT SendMessage(
  HWND hWnd,          //接收消息的目标窗口
  UINT Msg,            //消息标志
  WPARAM wParam,       //第一个消息参数
  LPARAM lParam      //第二个消息参数
);

 可以将hWnd的参数设置为HWND_BROADCAST,表示系统所有的非子窗体广播此消息。

为了避免调用线程陷入永久的等待状态,可以用SendMessageTimeout代替SendMessage:

LRESULT SendMessageTimeout(
    HWND hWnd,          //窗口句柄
   UINT Msg,              //消息标记
   WPARAM wParam,   //第一个消息参数
   LPARAM lParam,     //第二个消息参数
   UINT fuFlags,         //消息发送选项
   UINT uTimeout,     //超时,以毫秒为单位
   PDWORD_PTR lpdwResult,  //返回值,依赖于特定的消息
);

关键是fuFlag参数,它决定了该如何发送该消息,fuFlag参数的值及含义如下表:

说  明
SMTO_ABORTIFHUNG 如果目标线程处于挂起状态,调用线程将不等待超时而立即返回
SMTO_BLOCK 阻止调用线程在目标线程处理完消息之前处理其他请求
SMTO_NORMAL 在等待目标线程处理消息时,允许调用线程处理其他请求
SMTO_NOTIMEOUTIFNOTHUNG 对于XP/WIN2000有意义:如果目标线程未挂起,调用线程即使发生超时也会等待目标线程处理完该消息

 

 

 

如果调用成功,SendMessageTimeout会返回非0值;如果调用失败或发生超时,则返回0。为了防止调用线程被无限等待,可以将fuFlag参数设为SMTO_BLOCK,并设置一定的超时时间。

说明:如果是广播消息,假定有两个目标窗口将处理该消息,那么目标线程将总共有2*uTimeout毫秒的等待期。

CWnd::SendMessage对SendMessage进行了简单的包装,它验证窗口句柄的有效性,然后调用SendMessage API函数:

_AFXWIN_INLINE LRESULT CWnd::SendMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
    ASSERT(::IsWindow(m_hWnd));
    return ::SendMessage(m_hWnd, message, wParam, lParam);
}

提示:CWnd没有提供对SendMessageTimeout的包装。

同属于SendMessage系列的API还有SendNotifyMessage和SendMessageCallback,其行为特性介于PostMessage和SendMessage之间。

SendNotifyMessage函数:

BOOL SendNotifyMessage(
  HWND hWnd;         //窗口句柄
  UINT Msg;          //消息标志
  WPARAM wParam,     //第一个消息参数
  LPARAM lParam      //第二个消息参数
);

      如果hWnd窗口由调用线程创建,那么其行为特性跟SendMessage相同,这时将等待消息处理完毕后才返回。如果hWnd由另一线程创建,其行为特性则与PostMessage相同,它不必等待目标线程处理完该消息而直接返回。

SendMessageCallback函数:

SendMessageCallback的行为特性类似于PostMessage,也是在发出消息后,不等待目标窗口处理该消息就立刻返回,但它允许消息处理完毕后,让系统执行指定的函数。

BOOL SendMessageCallback(
   HWND hWnd,                //窗口句柄
   UINT Msg,                 //消息标志
   WPARAM wParam,            //第一个消息参数
   LPARAM lParam,            //第二个消息参数
   SENDASYNCPROC lpCallBack, //回调函数
   ULONG_PTR dwData          //应用范围内的数据
);

SENDASYNCPROC是回调函数的类型,它具有如下形式的签名:

VOID CALLBACK SendAsyncProc(
   HWND hwnd,        //目标窗口的句柄
   UINT uMsg,        //消息标记
   ULONG_PTR dwData, //应用范围的数据
   LRESULT lResult   //消息处理结束,依赖于特定的消息
);

传入回调函数的dwData正是在SendMessageCallback中的dwData参数指定的。

posted on 2013-07-15 15:59  尘土•狼  阅读(890)  评论(0编辑  收藏  举报