当前位置:C++技术网 > 资讯 > 自定义消息宏WM_USER如何避免与系统消息宏冲突

自定义消息宏WM_USER如何避免与系统消息宏冲突

更新时间:2016-02-02 22:44:09浏览次数:1+次

    在要用自定义消息实现程序的通信时,我们要确定一个特定的消息,也就是要确定这个消息的ID。而我们常见的消息都是WM_开头的宏表示的,实际上消息宏的本质就是一个数字而已。Windows定义了各种宏,以方便使用消息。各种宏可以让程序员快速识别每一个宏表示的消息的含义。如果消息的标志都用数字,那么多消息简直就是一个噩梦。这是宏的一个好处。
    然而我们自定义的消息,则完全要程序员自己来确定消息的标志ID数值。系统自定义的消息ID都代表了特定的消息,系统或者程序也会对这些消息进行处理。如果程序员随意设置一个数字作为自定义消息ID,一旦与系统消息定义的数字相同,则产生ID冲突。
    产生消息ID冲突会出现什么问题呢?好吧,我解释一下。如果你用下面的语句发送一个自定义消息给窗口:

SendMessage(hwnd,15,NULL,NULL);
     然后你期待在窗口过程中这样处理:
switch(message)
{
    case WM_PAINT:
        //客户区绘制代码
        break;
    case 15:
        //这是我的自定义消息处理过程
        break;
    //其他消息处理过程
}
     你以为这样就可以实现效果了。实际上,编译就不会通过,有语法错误。你是不是觉得很奇怪呢?你会得到这样的提示:case标签值已经出现在此开关中。经验比较少的人就一下子懵了,不知所措了。经验多的知道,这是case中的值重复写了。你可以将光标放在各个case标签值上,你会发现,WM_PAINT的值为0x000F,也就是十进制的15。这样就同时写了两个15作为case值,自然就出现语法错误了。
    这是一个比较幸运的,因为编译时就出现了问题,问题容易发现。然而,如果你这样自定义了一个消息值后,然后刚好WM_PAINT没有自己处理,而是默认处理了,就不会有这样的语法错误。编译正常,但是你的代码逻辑就会出问题。因为15是WM_PAINT消息的ID值,也就是说,你这里就相当于处理了WM_PAINT。然而你本意并不是想这样。这也导致你要在自定义消息里处理的事情并不是客户区重绘消息WM_PAINT要做的事情。而客户区要做的事情又被你这个消息处理拦截了。所以,就会出现客户区重绘不正常,即界面不正常,也会出现自定义消息不管用。没有经验的人,就真不知道问题出在哪了。
    这是自定义消息与系统定义的消息ID冲突的问题。所以,Windows给了自定义消息ID的确定方法,即使用WM_USER宏作为自定义消息ID值的起始值,然后往上加,都可以作为自定义消息ID值。在VS2010中查看到的WM_USER宏的值为0x0400,即十进制的1024.也就是说,系统自定义的消息ID小于1024。这样就将系统消息ID值与用户自定义消息ID值划分一个明显的界限。只要你用WM_USER、WM_USER+1、WM_USER+2...都不会与系统消息ID冲突。为什么不用直接的1024或者1024+呢?不是不可以,而是不推荐。万一新系统的消息变多,然后系统消息超过了1024,那么Windows会重新定义WM_USER的值,让自定义消息ID值起始值变大,来与系统消息ID值隔离。而你如果定义死了自定义消息值,就在新系统中还是可能出现消息ID冲突。
    所以为了避免这些问题,形成良好的编程习惯,建议使用WM_USER作为起始消息值来设置自己的自定义消息ID值。如果你觉得这样的WM_USER+1麻烦,你再定义一个宏即可,如:
#define MY_MSG1 WM_USER+1
#define MY_MSG2 WM_USER+2
     这样还是很方便哦,也可以让程序不会再出现消息ID冲突了。WM_USER宏的设计,也就是好在这里。这也体现微软设计的人性化和健壮性好。这也是让程序员减少程序出错的方法,请程序员自己要学会使用。再看见WM_USER不要在陌生害怕了,其实WM_USER就是一个自定义消息的起始数字罢了,为的就是不与系统消息冲突,仅此而已。