当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 利用钩子实现菜单阴影效果

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 利用钩子实现菜单阴影效果


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 81 ::
收藏到网摘: n/a

利用钩子实现菜单阴影效果


作者:成真


下载源代码


    也许有很多人曾和我一样, 对Office XP里面的菜单的阴影效果羡慕不已,它不需要在Windows XP 中就可以在菜单后面显示阴影, 当然在Windows XP中, 已经完全支持菜单阴影了。虽然我们不一定很有必要自己来实现这个较难实现的效果。但是正如有很多人想实现那种IE风格的菜单栏一样,尽管它 们并不能为我们带来更多实用的功能, 却可以使我们的程序看起来与众不同。:)
    菜单也是一个窗口, 假如我们能得到它的窗口的句柄, 要实现像添加阴影这样的效果, 就不会很难了。可惜我们根本找不到这个窗口是在哪里被创建的,也没办法很容易地取得它的窗口句柄,甚至几乎难以相信它是一个窗口,因为我实在找不到它的窗口句柄啊。经过对许多别人已经做好的类的源代码的"研究", 我终于找到了一个方法。那就是万能的钩子,如果说在Windows里面抓"人",连钩子也办不到的话,那我就不知道该用什么方法实现了,呵呵。
    下面我就一起来看看如何抓到这些"可恶"的家伙吧。为了便于移植,我们就写一个专用的类吧,就取名为CMenuWndHook。添加两个静态成员先:

static CMap m_WndMenuMap;static HHOOK m_hMenuHook;
   被我们抓到的这些家伙肯定不止一个,我们需要一个映射模板类来保存它们的句柄和对应的CMenuWndHook 类对象的指针。m_hMenuHook则为我们将要创建的钩子的钩子句柄。再在CPP文件中初始化它们:
CMap CMenuWndHook::m_WndMenuMap;HHOOK CMenuWndHook::m_hMenuHook = NULL;
下面再添加两个函数来做安装与卸载hook之用, 它们都是静态函数:
void CMenuWndHook::InstallHook(){ if (m_hMenuHook == NULL) { m_hMenuHook = ::SetWindowsHookEx(WH_CALLWNDPROC, WindowHook,	AfxGetApp()->m_hInstance, ::GetCurrentThreadId()); }}
Windows之下一般用上面的SetWindowsHookEx API函数来安装HOOK,它的函数原型如下:
HHOOK SetWindowsHookEx(int idHook, //钩子的类型,即它处理的消息类型      	HOOKPROC	lpfn,	//子函数的入口地址,当钩子钩到任何消息后先调用这个函数。	// (如果dwThreadId参数为0,或是一个由别的进程创建的线程的标识,	//lpfn必须指向DLL中的钩子子程。除此以外,lpfn可以指向当前进	//程的一段钩子子程代码)      	HINSTANCE	hMod, //应用程序实例的句柄。标识包含lpfn所指的子程的DLL。	// 如果dwThreadId标识当前进程创建的一个线程,	//而且子程代码位于当前进程,hMod必须为NULL。	//可以很简单的设定其为本应用程序的实例句柄。      	DWORD	dwThreadId //与安装的钩子子程相关联的线程的标识符。	//如果为0,钩子子程与所有的线程关联,即为全局钩子。	//但这时,你钩子只能是放在DLL中。      	); 

    函数成功则返回钩子子程的句柄,失败返回NULL。 我们用到的是WH_CALLWNDPROC类型的钩子,它使你可以监视发送到窗口过程的消息, 系统在消息发送到 接收窗口过程之前会调用你指定的WH_CALLWNDPROC Hook 子程,这样你就可以等它们自投罗网,然后就可以 对它们为所欲为了。 卸载钩子就简单多了,只需要调用UnhookWindowsHookEx即可,当然,我们还需要额外做一点清理工作:

void CMenuWndHook::UnInstallHook(){ POSITION pos = m_WndMenuMap.GetStartPosition();	while (pos != NULL) { HWND hwnd; CMenuWndHook *pMenuWndHook;	m_WndMenuMap.GetNextAssoc(pos, hwnd, pMenuWndHook);	delete pMenuWndHook;	pMenuWndHook= NULL;	}	m_WndMenuMap.RemoveAll();	if (m_hMenuHook != NULL)	{	::UnhookWindowsHookEx(m_hMenuHook);	} } 
    在介绍如何安装钩子时,提到要一个钩子子程,这个子程必须按下面的格式声明,否则不能使用:
LRESULT CALLBACK WindowHook(int code, WPARAM wParam, LPARAM lParam); 函数名随意,同样把它声明为静态函数,下面各位注意了,我们的逮捕行动就是在这个函数中展开的:
LRESULT CALLBACK CMenuWndHook::WindowHook(int code, WPARAM wParam, LPARAM lParam){	//如果你安装的是WH_CALLWNDPROC类型的钩子的话,系统就会传递一个这个家伙的指针:	CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;	while (code == HC_ACTION)	{	HWND hWnd = pStruct->