Tag:开源控件 , 源码下载 , 控件开发 , 控件美化 , 窗体换肤 , Skin , QQ表情 , Windows API , GDI+编程 , SQLite , Socket , 控件透明 , 下拉控件 , HTML 解析器 , 图片水印 , ScrollBar(滚动条) , Google Sitemap , 数据库 , SQL , WinForm , P/Invoke , OwnerDrawSystemMenu 个性化系统菜单 , 控件美化扩展

 
您的位置: >> 首页 >> C# 视角 >> C# 利用HOOK实现自绘窗体系统菜单

C# 利用HOOK实现自绘窗体系统菜单

2009-10-11  来自:CS 程序员之窗  字体大小:【  
  • 摘要:C#利用HOOK技术,给窗体的系统菜单加上自绘属性(MF_OWNERDRAW),然后通过WM_DRAWITEM消息绘制漂亮的个性化的系统菜单。

实现对系统菜单的自绘是非常麻烦的事情,花了不少时间,虽然实现了,但是还是不是很满意,因为还会闪烁,用了很多方法没能解决,就暂时这样先了。先来看看最后的效果:

先说说最开始的想法,因为我原来以为这是不会很难实现的一个东西,做了才知道,这个东西还真是特别,用正常的办法处理是不行的。

第一次尝试:通过得到系统菜单的句柄,然后通过截取消息就可以对它进行绘制了,不过这个系统菜单很特别,并不是通过它本身的句柄来处理绘制消息的,失败。

第二次尝试:窗体弹出系统菜单的时候后产生一个WM_ININTMENUPOPUP消息,拦截这个消息,给每个菜单项加上自绘属性,然后通过WM_MEASUREITEMWM_DRAWITEM消息计算菜单的大小和绘制菜单。这样可以绘制菜单了,但是不能绘制它的背景被边框,还有就是当鼠标在菜单上移动后,菜单没有重新绘制,然后就变的什么都没有了……,又失败了。

第三次尝试:俗话说,失败是成功他妈,继续再接再厉。通过GoogleBaidu,翻了一页又一页,终于知道系统菜单窗口创建的类名为"#32768",那在它创建的时候得到他的句柄,然后截取他的消息进行处理总行了吧,这次总算没有让我失望,呵呵。然后结合第二次的尝试,就得到了最终的方法:

第一步:HOOK,通过WM_CREATE消息得到菜单绘制窗口的句柄,通过它实现菜单背景、边框的重绘和鼠标移动后重新刷新窗口。在收到WM_DESTROY消息后,释放获得的菜单句柄。通过WM_INITMENUPOPUP消息给每一个菜单项添加上自绘属性(MF_OWNERDRAW),并得到菜单的父窗体的句柄。在WM_UNITMENUPOPUP消息后释放菜单的父窗体的句柄。

第二步:实现一个OwnerFormNativeWindow类,这个类的功能是通过菜单的父窗口的句柄,截取WM_MEASUREITEMWM_DRAWITEM消息,计算每个菜单项的小小和绘制每一个菜单项。

第三步:实现一个HookMenuNativeWindow类,这个类的功能是通过系统菜单的窗口句柄,

截取相应的绘制消息,绘制菜单的背景和边框和鼠标移动后刷新菜单窗口。需要注意的是鼠标移动后刷新窗口的消息不是WM_MOUSEMOVE,而是一个没有命名的消息:0x1e5

    第四步:实现一个SystemMenuRender类,这个类主要是实现对系统菜单的绘制。

最后需要说明的是,各个Windows版本,获取菜单信息的参数设置不同和绘制需要处理的消息也不同,我没有环境进行测试,只在XP下运行了,在其他系统上可能会有先东西需要改动。(原文)最后来看看关键的代码:

public class OwnerDrawSystemMenuHook : IDisposable
{
Fileds

Constructors

Properties

HookProc Methods

Windows Message Methods

Helper Methods

IDisposable 成员

OwnerFormNativeWindow Class

HookMenuNativeWindow Class
}

声明:

本文版权归作者和CS 程序员之窗所有,欢迎转载,转载必须保留以下版权信息,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

作者:Starts_2000

出处:CS 程序员之窗 http://www.csharpwin.com

你可以免费使用或修改提供的源代码,但请保留源代码中的版权信息,详情请查看:

CS程序员之窗开源协议 http://www.csharpwin.com/csol.html