请教一个MSDN上查不到WM类消息?

homezj 2007-03-27 12:44:39
好久没来CSDN了,也带来个最近刚遇到问题,有没有解不重要,主要是向各位朋友问个好,顺便送点技术分,当然,要符合版规,有线索价值才行,灌水是没分的。

自绘标题栏时,处理了WM_NCCALCSIZE、WM_NCHITTEST、WM_NCACTIVATE、WM_NCPAINT等消息,处理WM_NCHITTEST时,对于NC区我只返回HTCAPTION与HT边框有关的共9个结果,其余均为HTCLIENT。经过这样处理后,不管窗体是什么样式,标题栏与边框应该都是我控制了,可我发现在窗体显示后,鼠标首次移入标题栏或边框时,最大最小及关闭按钮总会被重绘(窗体的WS样式没有去掉这些按钮的情况下)!
经对消息做了一下分析,发现有一条值为&HAE的消息,若滤掉这条消息,按钮就不会重绘。可这条消息我查了一下MSDN,没有找到,我的资料中只有它前面的一个值WM_NCXBUTTONDBLCLK=&HAD,在后面直到&HFF都是空白,按理说它应是一条NC类消息。MSDN中没有,说明它可能是新定义的,哪位能提供这条消息的说明呀?

附:收到这条消息时,wPram值为&H1001,lPram为0
这条消息,是在WM_NCHITTEST返回首个大于HTCLIENT的值之后,并在WM_SETCURSOR消息之前收到,只有一次。另外,我说的情况是在WinXP下采用XP样式时才有,若采用Windows经典样式,直接就是WM_SETCURSOR,而没有这条消息,估计Win98下也是这样。虽然滤掉这条消息,按钮意外重绘的问题就解决了,但我还是非常想了解这条新消息的目的与用途。
这条消息用Spy+拦截也没有给出消息名,而标为未定义。没消息名,查资料真是太难了呀!
...全文
675 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
homezj 2007-04-05
  • 打赏
  • 举报
回复
啊!终于等来知情者了,neil_cn太感谢了你了!

搜了一下,这两个消息百度根本就没有找到,还是Google历害,找到6条!真少呀^_^其中5个E文条目,属同一个来源;还有一个不知什么文(可能是俄文吧),没发现官方文档,大致看一下,线索又断了,有位网友在win32k.sys中找到了这两个消息名,没了下文。另外看到一个可能是较权威人物的回信:
There is no need to add support for that purely internal XP messages.
Have a look at the WmAltVkN message sequence how it copes with 0x00AE:
it just marks it 'optional' and has a comment /* XP */ for it.

也许MS也认为这就是两个“无需支持的XP内部可选消息”,也就不做说明了。

它们的wParam与lParam参数是何意义,始终没有任何人提及,总之,既然多数人认为过滤掉这两条消息是安全的,实在不懂,就不管了,吃掉它们即一了百了!

不知 neil_cn 能否再提供些更进一步的资料?
neil_cn 2007-04-05
  • 打赏
  • 举报
回复
WM_NCUAHDRAWCAPTION 0xae
WM_NCUAHDRAWFRAME 0xaf

XP 有效,2003我还没捕获到这个消息(我不用XP风格的样式),是用来重绘启用了XP风格样式的窗体标题和边框
dx136 2007-04-04
  • 打赏
  • 举报
回复
嘿嘿嘿嘿我也来
Red_angelX 2007-04-02
  • 打赏
  • 举报
回复
各位大虾,想自己画程序边框该如何实现呢?(可以拉伸)
homezj 2007-04-02
  • 打赏
  • 举报
回复
早上又抽空分析了一下,DefWindowProc重绘系统按钮的时机,要想自己管理NC区,首先不管什么情况下,有两种情况必须做处理:
1、WM_NCHITTEST要过滤,对NC区,只可返回HTCAPTION与HT边框等与重绘无关的结果,系统按钮重绘与响应自已处理。其实,一律返回HTCLIENT也是可行,但要在窗体移动或改变大小时处理鼠标指针、发送消息或调用DefWindowProc,有点烦。当然返回HTCAPTION与HT边框,在非XP样式下,也有系统自动重绘的干扰,不过相对好处理一些,后面讨论。

2、还要注意WM_NCACTIVATE也很重要,失活时,DefWindowProc也会自做主张重绘失活的标题栏,这条消息不能滤掉,否则会有问题,解决办法:先交给DefWindowProc,后重绘自己的。这个消息还要注意一点,千万别给VB的窗体过程处理,VB很烦,在这个消息处理时,它会自行根据它自已保存的Menu数据,绘上菜单,而不管你是否调用过 SetMenu hWnd, 0。

除去上面的问题,我发觉&HAE这条消息的作用,还是很大的,只要滤掉它,NC区就基本掌控了。

当然不能忘了还有经典样式,这种样式下没有&HAE消息,我基本摸出了系统按钮重绘的几个时机(注意:我讨论的都是在没有禁掉WS_CAPTION等样式的前提下,禁掉的话,将没有下面的问题):
1、DefWindowProc首次绘制系统按钮,这种绘制只有一次,可以用个全局变量做标志,在窗体存活期内只处理一次。这种首绘时机又分两种情况:
a、最初我认为是在WM_SETCURSOR消息中,wParam包含首个大于HTCLIENT值时,现在看来,HTCAPTION是个例外,系统在鼠标指针不改变时,并不绘制系统按钮,所以在这个消息中不宜针对HTCAPTION,重绘自己的标题栏;
b、在WM_NCLBUTTONDOWN消息中首次出现HTCAPTION时,我们可调用LockWindowUpdate hwnd,因为其后会有一条WM_SYSCOMMAND消息,在这条消息中,会收到SC_MOVE命令,这时,LockWindowUpdate 0,然后,再画一次自己的标题栏。
以上两种,加上滤掉&HAE,总共是三种首绘时机,只要抓住其一,另两个就不用管了,所以三种情况都要去抓,任一抓到后,全局标志跟着改变,另两种就可跳过去。同样,这几处消息最好要交给DefWindowProc,若CallWindowProc调用VB的窗体过程,可能会添乱的。

2、VB代码中Me.Caption改变时,这种情况只需处理WM_STYLECHANGING,在新Style中若存在WS_CAPTION,则可重绘一次自己标题栏。当然,需要的话,此时应该重取一次窗体标题,用直接把WM_GETTEXT交给CallWindowProc的方式。

要想做到最大兼容性,上面所有问题都要处理;要想最省事,禁掉WS_CAPTION等样式或不用在经典样式系统下,后两种情况就不用管了。

以上分析,只是实测结果,可能还会有没遇到的问题,欢迎补充。

很想给&HAE取个名字,暂叫它WM_NCREDRAW吧,不知道MS同意不同意^_^
homezj 2007-04-02
  • 打赏
  • 举报
回复
上面笔误写错了一点:“直接把WM_GETTEXT交给CallWindowProc的方式”
应改为:“直接把WM_GETTEXT交给DefWindowProc的方式”

一般情况下,自己处理的消息若仍需窗体过程配合,都可直接交给DefWindowProc。CallWindowProc不是不行,就是有些绕路。不过,Active类的几个消息是个例外,它是VB很多处理的基础,得不到它们,VB会发疯的^_^

上面的朋友,画边框不是问题,想怎么画都行,我想最少也要画几根线吧:=)
用它拉伸窗体,可由消息控制,也可直接调用默认窗体过程,举个最简单例子:拉右边框动作,可写这样一句
DefWindowProc hwnd, WM_NCLBUTTONDOWN, HTRIGHT, 0
DengXingJie 2007-03-31
  • 打赏
  • 举报
回复
收藏
danielinbiti 2007-03-30
  • 打赏
  • 举报
回复
收藏
homezj 2007-03-30
  • 打赏
  • 举报
回复
禁掉CAPTION当然不能简单的一个SETWINDOWLONG,这我在前面提过一点,可能上面的朋友没注意,必须还要处理WM_STYLECHANGING,若需要,WM_STYLECHANGED也不能漏。

不管是外部调用SETWINDOWLONG或VB调用Me.CAPTION,都可这样滤掉。只有这样,才叫完整意义上的“禁掉”,否则只能叫“改变”。

CAPTION等样式改变,窗体不会自动重绘,上面朋友可能是受VB的CAPTION影响,才得出这个结论的,看看MSDN是怎么说的:

Certain window data is cached, so changes you make using SetWindowLong will not take effect until you call the SetWindowPos function

If you have changed certain window data using SetWindowLong, you must call SetWindowPos to have the changes take effect. Use the following combination for uFlags: SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED.

这里所指的窗体数据主要是一些对窗体外观产生影响的样式,一般调用SetWindowLong改变样式,都是在窗体显示或Resize之前,这些是无需再调用SetWindowPos的,因为其后窗体肯定要重绘!所以,容易让人误以为SetWindowLong能立即产生效果。

加上SWP_FRAMECHANGED标志是关键,它会强制发送一条WM_NCCALCSIZE消息,这条消息处理的结果,若产生非客户区或客户区的任何大小或位置改变,窗体就会接着收到重绘消息,当然,这条消息返回值也可强制产生重绘消息。
hanyue112 2007-03-30
  • 打赏
  • 举报
回复
只要窗体的CAPTION改变,就会重绘.手动重绘要调用API: DRAWMENUBAR
W2K和XP对这个反映确实不一样.W2K的重绘不会改变MAXBUTTON MINBUTTON 等等的状态.XP会把他们全部重置.如果你用SETWINDOWLONG的方法禁止了MAX/MIN BUTTON,那么一但CAPTION改变,先前的SETWINDOWLONG会失去效果,需要重新SETWINDOWLONG.
韧恒 2007-03-30
  • 打赏
  • 举报
回复
我觉得还是不要修改窗口风格,完全从处理消息入手,因为这样更有通用性,你甚至可以应付各种窗体及对话框。包括程序打开的MSGBox、打开、保存对话框、目录浏览对话框等等。

至于&HAE,我昨晚忽然想到一个答案,觉得很搞笑:
你说你向盖茨发过Email,但他没有回应,通常我们会理解为“领导”很忙没时间,或者是技术壁垒,或者他根本没看到....等等理由,但我却想另外一个理由,盖茨不好意思向你说明这个消息的作用,因为MS也用了一个"比较龌龊"的方法。哈...
hanyue112 2007-03-30
  • 打赏
  • 举报
回复
恩.我的意思就是在VB里面重新给CAPTION附值.我的解决方法是每次CAPTION后SETWINDOWLONG.并没有截获任何消息.
homezj 2007-03-29
  • 打赏
  • 举报
回复
To:songyaowu

前面说过,XP风格下才有这个消息,经典风格(Win2000就是)下是在WM_NCHITTEST返回首个大于HTCLIENT的值之后,接着会是一个WM_SETCURSOR消息,这时会发生系统按钮重绘。另外,改变VB的Caption时也会发生。

对于经典风格,我的处理是设个全局标记,在处理首个对NC的WM_SETCURSOR消息时,先调用DefWindowProc后自已重绘标题,为防闪烁,可用LockWindowUpdate。至于Me.Caption就不要用了。若非要用,需在使用后自己再重绘一遍,重绘时机,可选在处理WM_STYLECHANGED时。

当然这种方法比较龌龊!一劳永逸的方案的还是禁掉WS_CAPTION、WS_MINIMIZEBOX等样式,自已在WM_NCCALCSIZE中安排非客户区。其实既然要自绘窗体风格,整个外观必然是要全部自绘的,根本无需系统自动为我们画任何东西,所以我认为这才是最佳方案,这也将没有&HAE这个消息的困扰,而且比那些完全去掉非客户区的方案要合理得多。
韧恒 2007-03-29
  • 打赏
  • 举报
回复
我一直用Win2000做开发,在win2000中好象收不到这则消息啊。但那按钮的确又被重绘,难到XP和win2000是在不同的消息中处理了这个动作?如果这样我们的工作会更加复杂了。

强烈关注中 ......

韧恒 2007-03-29
  • 打赏
  • 举报
回复
Mark!!!!
"自绘标题栏时,处理了WM_NCCALCSIZE、...... 最大最小及关闭按钮总会被重绘(窗体的WS样式没有去掉这些按钮的情况下)!" 这个问题已经困扰我至少3年了,我没有找到更好的办法。我一直梦想着做一个能改变窗口风格的控件,正象楼主所说边框和标题栏的尺寸问题虽然我未进行测试,但我想可以解决,但就是这个窗口非客户区的这三个按钮的绘制问题让我一直未能如愿。
homezj 2007-03-29
  • 打赏
  • 举报
回复
Me.Caption的内部实现,我推测为类似以下代码

Public Property Let Caption(ByVal vData As String)
Dim a() As Byte
a = StrConv(vData & vbNullChar, vbFromUnicode)
DefWindowProc Me.hwnd, WM_SETTEXT, 0, VarPtr(a(0))

SetWindowLong Me.hwnd, GWL_STYLE, 原样式 or WS_CAPTION '根据设计时的设定再Or WS_SYSMENU等Flag

SetWindowLong Me.hwnd, GWL_EXSTYLE,原扩展样式

在修改样式时若发现实际样式与内部设定不同,VB还会调用一次
SetWindowPos Me.hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOACTIVATE Or SWP_NOOWNERZORDER

Or SWP_FRAMECHANGED

End Property

Me.Caption赋值后,没样式变化时会触发五个消息,&HAE,和两对 WM_STYLECHANGING、WM_STYLECHANGED,有样式变化的话,其后还会有

一系列与NC重绘有关的多个消息

为什么改变Caption,没拦截到WM_SETTEXT,因为VB没用SetWindowText或SendMessage,而是直接交给了DefWindowProc,这个处理将会触

发&HAE消息(XP风格下且有系统按钮样式)

因为改变Caption需涉及窗体样式变化,所以VB要将窗体样式统一为自己内部保存的样式设定。

这就是为什么我们有时改变BorderStyle属性后,要再调用Me.Caption=Me.Caption才会看到效果的原因。

&HAE消息看似与Caption有关,但本质上它还是要重绘系统按钮,感觉为什么在XP风格下才会新增这个消息,似乎是因为XP下,系统按钮

有MouseOver效果,而传统风格没有。
这个消息的lParm参数似乎没用,wParm参数在WM_NCHITTEST返回首个大于HTCLIENT的值之后,是&H1001,在Me.Caption赋值后是&H9,对

这我就实在猜不出其含义了!
xiaolei1982 2007-03-29
  • 打赏
  • 举报
回复
帮顶!!!
proglovercn 2007-03-29
  • 打赏
  • 举报
回复
学习……
  • 打赏
  • 举报
回复
都是 高人啊
rainstormmaster 2007-03-29
  • 打赏
  • 举报
回复
这个消息应该不是VB自定义的消息.

可以肯定的是这个消息是一个新的消息,这个undocumented message,我们现在恐怕也无法他的相关资料了.

另外,关于改变Me.Caption我的看法是,这是个很神奇的语句,在使用了有关的api函数之后,要慎用
加载更多回复(12)

1,486

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧