当前位置:C++技术网 > 精选软件 > 自定义窗口消息实现窗口通信即如何实现自定义消息

自定义窗口消息实现窗口通信即如何实现自定义消息

更新时间:2016-10-20 15:32:53浏览次数:1+次

    平时很少用到窗口自定义消息,此前知道大概怎么做,毕竟因为没有真正完整的去实现过,所以多少都是模糊的。今天一个功能点需要自定义消息了,所以就用上了。
    使用的情景是这样的:有两个窗口,每一个窗口都对应一个MFC窗口类处理消息。两个类之间没有任何关联,相互独立。我分别将两个类叫做类A和类B吧,两个窗口对应的就是窗口A和窗口B。
    窗口A是主窗口,拥有大量的资源。类A管理着众多的网络客户端,是一个TCP服务器管理者身份。我这个软件就是服务器后台监控软件。而窗口B则是一个设置窗口,只是用来修改配置用的。窗口B设置好参数后,本来是直接将参数保存到配置文件或者数据库即可。不过有一组参数需要在设置修改后,要在主窗口的一些地方做处理。在设置修改后,就需要用到类A去进一步同步处理其他信息,我这里就是去发广播,需要用类A去广播参数的更改,将参数发给所有连接着的客户端。
    能够发广播的各种支持自然只在类A中有效,而类B无法获取到类A的资源。不过,通过分析,窗口B参数修改之后,参数是存储到了配置文件了的。唯一需要与类A通信的就是告知它参数有改动,需要去做广播参数了。那么此时就需要要一个简单的通知就行了。
    开始想着要不要通过全局变量之类的去做同步,不过想想也挺麻烦的。类A那边要么要不断的检测全局变量的变化。要么用定时器,要么开一个线程循环检测。不管哪样,代价都挺高的。用回调函数倒是可以,不过耦合性太高了,因为一个回调函数关联起来两个类的关系。
    因为这是两个窗口对应的处理类,所以我们可以直接利用窗口消息来简单传递一下消息。只需要调用SendMessage或者PostMessage消息即可。不过推荐使用PostMessage,因为PostMessage只要将消息推送到对方窗口的消息队列即可,就可以立即返回了。而SendMessage要等待对方窗口处理完消息才返回。我只需要告知即可,所以把消息发送到消息队列,任务就完成。
    两个函数的声明如下:
BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam );
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

    两个函数的原型一样的。我们这里只需要传递一个消息,用不到参数。所以后面两个参数全部为0.第一个参数为窗口的句柄,我们自然可以获取到窗口的句柄咯。最后一个就是Msg参数,这个就是消息名称。
    回想一下,我们平时处理的各种窗口消息,都是系统预定义好的,每一个消息都有特定的意义。如此看到,我们自己需要的消息,系统肯定是没有提供的,所以我们需要自定义一个窗口消息。而消息只是一个特定的数值,我们看到的WM_CHAR这样的消息名称都是宏。
    系统定义的消息一般在一个数值范围之内的,如果我们用这个范围内的数值作为自定义消息的数值,可能就定义成系统已有的消息了,产生了冲突。为了不产生冲突,系统提供了一个自定义消息宏WM_USER,这个宏对应的数值作为基数,我们在此基础上加一个数值,就不会和系统的消息宏数值冲突了。
    我们就用WM_USER+1作为我们的自定义消息。但是看着这个名词,很别扭。那就定义一个新名称吧。
#define MSG_BOARD WM_USER+1

    后面我们就发送这个消息来通信。窗口A收到MSG_BOARD就表示参数已经修改了,需要广播了。宏定义的位置要在类A和类B都能看到的位置,或者在两个类中都定义一下。
    然后在类B修改了参数后,调用下面的代码:
::PostMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_BOARD,0,0);//通知窗口A即主窗口要广播参数了

    第一个参数就是主窗口的窗口句柄值,第二个参数就是消息,后面两个不用传递参数,默认为0即可。
    然后重点就在于自定义消息的处理了。
    我们先写好自定义消息的处理函数声明:
afx_msg LRESULT OnBoard(WPARAM wParam, LPARAM lParam);//广播消息处理

    然后在源文件中写好函数的定义:
LRESULT 主窗口类名::OnBoardRate(WPARAM wParam, LPARAM lParam)
{
    //在此处写处理消息的代码
    return 0;
}

    到这里都是很熟悉的。平时的消息处理都是这么干的。只是你要注意,这里只有两个参数,分别是WPARAM和LPARAM,因为MFC环境下,窗口句柄是类的成员变量,所以此处不必传参。而这个消息处理函数是专门处理这个消息的,在消息映射里指定了,所以也不需要传递消息这个参数。返回值类型为LRESULT,和窗口过程函数返回值一致。
    下面就要看看消息映射如何指定自定义消息和消息处理函数的关系了。同样,消息映射还是在主窗口类A的源文件中的消息映射对里指定:
BEGIN_MESSAGE_MAP(主窗口类名称, CDialogEx)
    ON_MESSAGE(WM_BOARD_RATE, OnBoardRate) 
END_MESSAGE_MAP()

    我们使用ON_MESSAGE宏将自定义消息和处理函数关联起来。到此,整个自定义消息处理以及消息的通信就构建完毕了。
    大家不熟悉的就是自定义消息宏WM_USER的使用和消息映射ON_MESSAGE宏的使用。其他的基本都熟悉,或者说PostMessage和SendMessage对于新手来说,可能不太熟悉。
    其实,也就这么一回事,很简单,是不是。记住,需要自己动手写一下,这样才能真正领会。