Chinaunix首页 | 论坛 | 博客
  • 博客访问: 153879
  • 博文数量: 37
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 380
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-13 18:49
文章分类

全部博文(37)

文章存档

2010年(1)

2009年(19)

2008年(17)

我的朋友

分类:

2010-02-25 14:11:54

           因工作需要,最近在学习CEGUI库,不过今天在调试的时候发现一个奇怪的现象。我在鼠标按下的事件处理函数上设置一个断点,但是不管怎么样都跑不到按钮(通过CEGUI库生成的按钮)的事件函数。而把断点去掉让其裸跑就可以。
           后来发现该按钮事件是通过鼠标释放事件来激活。所以又在鼠标释放处理事件函数上设置一个断点,结果是当进入了鼠标按下事件断点后,压根就没有鼠标释放事件。而如果去掉鼠标按下事件上的断点,保留鼠标释放事件上的断点则可以正常运行。
           查了网上一些资料,发现这是windows的一个bug。MSDN压根就没讲。下面是原文
 

重载windows的ncarea来自绘窗口标题栏是条死路(在Vista系统上,如果主题带 有毛玻璃效果,那么无论你的窗口标题栏如何自绘,都会把系统的标题栏覆盖在自绘的标题栏上),因此自绘标题栏的唯一办法就是在客户区模拟非客户区,"伪 造"实现标题栏的功能。我的这篇文章有些误人。这篇文章的目的只是为了讲述以前曾经遇到的一个问题。

NCLBUTTONUP表示non-client left button up, 窗口的非客户区(也就是标题栏以及边框区域)的 鼠标左键点击被释放的消息。

 

旺旺的网页型插件是一个在独立进 程里的内嵌IE控件的普通窗口,为了让窗口的风格尽量和旺旺的风格一致,因此我重画了窗口的标题栏和最小化按钮等 (另外一种办法就是干脆不要标题栏,

直接自己在客户区里仿造标题 栏)。

 

最小化按钮的处理是响应WM_NCLBUTTONUP消息,收到该消息并且鼠标在最小化图标内,则将窗口最小化。

 

今天同事发现网页型插件的窗口的 最小化按钮点击后,不太灵。我找了找原因,发现当在标题栏上点击鼠标左键后,能收到WM_NCLBUTTONDOWN(按下的消息),但是不一定能收到WM_NCLBUTTONUP

的消息(释放左键的消息)。Google了一下,发现Windows的确有这个问题(MSDN干脆完全就没说明)。当在非客户区点击鼠标左键并释放时,系统会发送窗口的WM_LBUTTONUP(注意不是WM_NCLBUTTONUP,这是客户区的鼠标释放消息, 但是我们现在在非客户区释放鼠标如之奈何)消息到线程的消息队列,但线程的消息队列压根就不把这个消息发送给这个窗口的窗口过程!

 

既然不发送到窗口过程,那哥们儿 是怎么发现的呢?他是通过spy++仔细看产生的消息发现的 (因为spy++截取窗口的原理是通过使用HOOK的方式,而我的代码里为了处理IE的热键也用到了HOOK,

但是由于粗心没有针对所有消息都 调用CallNextHookEx,以致于我用spy++看的时候没有这个哥们儿牛逼,调的半死,被工具陷害,造化弄人(因为spy++也是hook,因为这个消息被我的hook独占了,它老兄就hook不到 了,因此也就看不见这个WM_LBUTTONUP消息了)

 

解决的办法基本原理就是当鼠标左 键在非客户区按下释放后,自己伪造发送一条WM_NCLBUTTONUP消息给 窗口过程。

因此要解决的核心问题是: 怎么判断当前鼠标左键在非客户区按下并释放了 (如果窗口过程收到了WM_NCLBUTTONDOWN,并且接着消息HOOK的回调函数里发现了WM_LBUTTONUP,就是表明

当前鼠 标在非客户区按下并且释放了,此时伪造WM_NCLBUTTONUP消息)

 

解决办法如下:

1.       响应非客户区鼠标按下的消息WM_NCLBUTTONDOWN 定义一个flag, m_bNCLButtonDowned = true; 表示当前在非客户区按下了鼠标左键

2.       使用WH_GETMESSAGEHOOK, hook整个线程的消息队列,从而得到在非客户区释放鼠标时的WM_LBUTTONUP消息(因为spy++就是这种方式,因此我们也可以采用这种方式,当然google里的那哥们使用的是mouse hook,忒复杂了些)

3.       hook回调函数里的WM_LBUTTONUP消息判断当前m_bNCLButtonDowned == true?非客户区里是否按下了鼠标左键,如果是,则PostMessage一个WM_NCLBUTTONUP,将真正的非客户区的

鼠标释放消息发送给窗口的窗口过程

4.       在窗口过程里的WM_NCLBUTTONUP的处理函数里判断m_bNCLButtonDowned == true?如果是,则执行代码,同时置位m_bNCLButtonDowned,表示当前已经释放了鼠标左键,因此鼠标左键没有按下

 

前辈试验出来的系统会发送WM_NCLBUTTONUP的时刻:

1.       双击标题栏

2.       在客户区按住鼠标左键,但是在 非客户区释放鼠标左键


阅读(2354) | 评论(0) | 转发(0) |
0

上一篇:Linux slab 分配器剖析[转]

下一篇:没有了

给主人留下些什么吧!~~