实现菜单阴影效果Word格式.docx

上传人:b****1 文档编号:5332060 上传时间:2023-05-05 格式:DOCX 页数:13 大小:44.08KB
下载 相关 举报
实现菜单阴影效果Word格式.docx_第1页
第1页 / 共13页
实现菜单阴影效果Word格式.docx_第2页
第2页 / 共13页
实现菜单阴影效果Word格式.docx_第3页
第3页 / 共13页
实现菜单阴影效果Word格式.docx_第4页
第4页 / 共13页
实现菜单阴影效果Word格式.docx_第5页
第5页 / 共13页
实现菜单阴影效果Word格式.docx_第6页
第6页 / 共13页
实现菜单阴影效果Word格式.docx_第7页
第7页 / 共13页
实现菜单阴影效果Word格式.docx_第8页
第8页 / 共13页
实现菜单阴影效果Word格式.docx_第9页
第9页 / 共13页
实现菜单阴影效果Word格式.docx_第10页
第10页 / 共13页
实现菜单阴影效果Word格式.docx_第11页
第11页 / 共13页
实现菜单阴影效果Word格式.docx_第12页
第12页 / 共13页
实现菜单阴影效果Word格式.docx_第13页
第13页 / 共13页
亲,该文档总共13页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

实现菜单阴影效果Word格式.docx

《实现菜单阴影效果Word格式.docx》由会员分享,可在线阅读,更多相关《实现菜单阴影效果Word格式.docx(13页珍藏版)》请在冰点文库上搜索。

实现菜单阴影效果Word格式.docx

下面再添加两个函数来做安装与卸载hook之用,它们都是静态函数:

voidCMenuWndHook:

InstallHook()

{

if(m_hMenuHook==NULL)

m_hMenuHook=:

SetWindowsHookEx(WH_CALLWNDPROC,

WindowHook,

AfxGetApp()->

m_hInstance,

:

GetCurrentThreadId());

}

Windows之下一般用上面的SetWindowsHookExAPI函数来安装HOOK,它的函数原型如下:

HHOOKSetWindowsHookEx(intidHook,//钩子的类型,即它处理的消息类型     

HOOKPROClpfn,

//子函数的入口地址,当钩子钩到任何消息后先调用这个函数。

//(如果dwThreadId参数为0,或是一个由别的进程创建的线程的标识,

//lpfn必须指向DLL中的钩子子程。

除此以外,lpfn可以指向当前进

//程的一段钩子子程代码)     

HINSTANCEhMod,//应用程序实例的句柄。

标识包含lpfn所指的子程的DLL。

//如果dwThreadId标识当前进程创建的一个线程,

//而且子程代码位于当前进程,hMod必须为NULL。

//可以很简单的设定其为本应用程序的实例句柄。

     

DWORDdwThreadId//与安装的钩子子程相关联的线程的标识符。

//如果为0,钩子子程与所有的线程关联,即为全局钩子。

//但这时,你钩子只能是放在DLL中。

     

);

函数成功则返回钩子子程的句柄,失败返回NULL。

我们用到的是WH_CALLWNDPROC类型的钩子,它使你可以监视发送到窗口过程的消息,系统在消息发送到接收窗口过程之前会调用你指定的WH_CALLWNDPROCHook子程,这样你就可以等它们自投罗网,然后就可以对它们为所欲为了。

卸载钩子就简单多了,只需要调用UnhookWindowsHookEx即可,当然,我们还需要额外做一点清理工作:

voidCMenuWndHook:

UnInstallHook()

POSITIONpos=m_WndMenuMap.GetStartPosition();

while(pos!

=NULL)

HWNDhwnd;

CMenuWndHook*pMenuWndHook;

m_WndMenuMap.GetNextAssoc(pos,hwnd, 

pMenuWndHook);

deletepMenuWndHook;

pMenuWndHook=NULL;

m_WndMenuMap.RemoveAll();

if(m_hMenuHook!

UnhookWindowsHookEx(m_hMenuHook);

在介绍如何安装钩子时,提到要一个钩子子程,这个子程必须按下面的格式声明,否则不能使用:

LRESULTCALLBACKWindowHook(intcode,WPARAMwParam,LPARAMlParam);

函数名随意,同样把它声明为静态函数,下面各位注意了,我们的逮捕行动就是在这个函数中展开的:

LRESULTCALLBACKCMenuWndHook:

WindowHook(intcode,WPARAMwParam,LPARAMlParam)

//如果你安装的是WH_CALLWNDPROC类型的钩子的话,系统就会传递一个这个家伙的指针:

CWPSTRUCT*pStruct=(CWPSTRUCT*)lParam;

while(code==HC_ACTION)

HWND 

hWnd=pStruct->

hwnd;

//截获WM_CREATE消息,为了保证不抓错"

,我们必须严格确定这是否是我们要抓的家伙,

//这样我们就可以在它们刚出头就把它们逮住:

if(pStruct->

message!

WM_CREATE&

&

pStruct->

=0x01E2)

break;

//是否为菜单类----------------------------------------

TCHARstrClassName[10];

intCount=:

GetClassName(hWnd,

strClassName,

sizeof(strClassName)/sizeof(strClassName[0]));

//再次确认它的身份(菜单窗口类的类名为"

#32768"

,且为6个字符长):

if(Count!

=6||_tcscmp(strClassName,_T("

))!

0)

//对不起,认错人了,pass:

-)

//是否已经被子类化------------------------------------

//我们抓到一个之后,会给它用SetProp挂个牌(后面会介绍)

if(:

GetProp(pStruct->

hwnd,CoolMenu_oldProc)!

=NULL)

//已经在编?

pass.

//抓到一个,给它登记注册(这个函数我会在后面介绍), 

而且不能登记失败,:

VERIFY(AddWndHook(pStruct->

hwnd)!

=NULL);

//下面该叫它去洗心革面了-----------------

//取得原来的窗口过程----------------------------------

WNDPROColdWndProc=(WNDPROC)(long):

GetWindowLong(pStruct->

hwnd,GWL_WNDPROC);

if(oldWndProc==NULL)

ASSERT(oldWndProc!

=CoolMenuProc);

//这个过程一样不能出错

//保存到窗口的属性中----------------------------------

//哈哈,给它打个记号吧(SetPropAPI函数是用来给一个窗口加上一个属性的,

//RemoveProp则是删除一个属性,GetProp是取得一个属性的值) 

//CoolMenu_oldProc为一字符数组,我在CPP文件的开头声明了它,表示你要

//添加的属性名:

constTCHARCoolMenu_oldProc[]=_T("

CoolMenu_oldProc"

//这里保存的是它的原来的窗口过程,这种该随身带的东西还是让它自己拿着比较好

if(!

SetProp(pStruct->

hwnd,CoolMenu_oldProc,oldWndProc))

//子类化----------------------------------------------

//这个不用我说了吧,这里我们用了偷梁换柱的方法,呵呵,这可是子类化的惯技了:

SetWindowLong(pStruct->

hwnd,GWL_WNDPROC,(DWORD)(ULONG)CoolMenuProc))

//没有成功!

!

唉,就放过他吧,虽然忙了半天了,不过这种情况我想是不可能发生的!

RemoveProp(pStruct->

hwnd,CoolMenu_oldProc);

//这句可是绝对不能少的,叫那些闲杂人等该干什么就干什么去,不要?

//嘿嘿,看你的程序怎么死吧!

returnCallNextHookEx(m_hMenuHook,code, 

wParam,lParam);

我们再来看看,怎么"

登记"

它们:

CMenuWndHook*CMenuWndHook:

AddWndHook(HWNDhwnd)

CMenuWndHook*pWnd=NULL;

if(m_WndMenuMap.Lookup(hwnd,pWnd))

//有这个人了,不用再登记了。

returnpWnd;

//给它分配个房间(牢房!

嘿嘿)

pWnd=newCMenuWndHook(hwnd);

if(pWnd!

m_WndMenuMap.SetAt(hwnd,pWnd);

//另外还可有一个对应的查找函数:

CMenuWndHook* 

CMenuWndHook:

GetWndHook(HWNDhwnd)

return 

NULL;

上面的函数和变量大部分都是静态成员,因为hook系统只要有一套就可以了到这里为止,坚巨的任务已经完成了一半,做下面的事,就得心应手多了。

下面是窗口的新过程,依然为一个静态的函数。

CoolMenuProc(HWNDhWnd,

UINTuMsg,

WPARAMwParam,

LPARAMlParam)

WNDPROColdWndProc=(WNDPROC):

GetProp(hWnd,CoolMenu_oldProc);

switch(uMsg)

//计算非客户区的大小--------------------------

caseWM_NCCALCSIZE:

{

LRESULTlResult=CallWindowProc(oldWndProc,

hWnd,

uMsg,

wParam,

lParam);

if((pWnd=GetWndHook(hWnd))!

pWnd->

OnNcCalcsize((NCCALCSIZE_PARAMS*)lParam);

returnlResult;

}

//当窗口的位置将要发生改变,在这里它一般发生在菜单被弹出之前,

//给你最后一次机会设置它的位置.

caseWM_WINDOWPOSCHANGING:

NULL)

OnWindowPosChanging((LPWINDOWPOS)lParam);

}break;

//为什么要响应这个消息呢?

我也不知道啊,我只知道,当菜单是以动画的方式弹出的时候

//系统是通过发送这个消息来绘制菜单的,wParam是对应的设备上下文句柄,不过我也不知

//道它到底是属于谁的.

caseWM_PRINT:

OnPrint(CDC:

FromHandle((HDC)wParam));

//这个就不同说了吧.

caseWM_NCPAINT:

OnNcPaint();

return0;

//菜单窗口被隐藏的时候,我也不知道这种情况会不会发生,:

(,主要是看到人家这样处理了.

caseWM_SHOWWINDOW:

OnShowWindow(wParam!

//菜单窗口被销毁的时候

caseWM_NCDESTROY:

OnNcDestroy();

returnCallWindowProc(oldWndProc,hWnd,uMsg,wParam,lParam);

下面就看如何慢慢实现这些消息的响应函数吧:

OnWindowPosChanging(WINDOWPOS*pWindowPos)

IsShadowEnabled())

//加一块区域来显示阴影-------

pWindowPos->

cx+=4;

cy+=4;

//为了绘制阴影,我们须要先保存这个区域的图像,以便绘制半透明的阴影.

IsWindowVisible(m_hWnd)&

!

if(m_bmpBack.m_hObject!

m_bmpBack.DeleteObject();

m_bmpBack.Attach(GetScreenBitmap(CRect(pWindowPos->

x,

y,

cx,

pWindowPos->

cy)));

OnNcCalcsize(NCCALCSIZE_PARAMS*lpncsp)

//留出一点区域来显示阴影-------

lpncsp->

rgrc[0].right-=4;

rgrc[0].bottom-=4;

上面我用到了两个全局函数,其中IsShadowEnabled是检测系统是否开启了菜单阴影(主要针对于WindowsXP,Windows2003及他更高的版本)如果系统已经给我们开启了阴影,我们还忙乎什么哦。

BOOLWINAPIIsShadowEnabled()

BOOLbEnabled=FALSE;

if(SystemParametersInfo(SPI_GETDROPSHADOW,0,bEnabled,0))

returnbEnabled;

returnFALSE;

其中SPI_GETDROPSHADOW在VC6里面没有被声明,你需要自已声明它:

#ifndefSPI_GETDROPSHADOW

#defineSPI_GETDROPSHADOW0x1024

#endif

另外还有GetScreenBitmap函数用于截取屏幕上指定区域内的图像:

HBITMAPWINAPIGetScreenBitmap(LPCRECTpRect)

HDC 

hDC;

hMemDC;

HBITMAPhNewBitmap=NULL;

if((hDC=:

GetDC(NULL))!

=NULL)

if((hMemDC=:

CreateCompatibleDC(hDC))!

if((hNewBitmap=:

CreateCompatibleBitmap(hDC,

pRect->

right-pRect->

left,

bottom-pRect->

top))!

HBITMAPhOldBitmap=(HBITMAP):

SelectObject(hMemDC,hNewBitmap);

BitBlt(hMemDC,0,0,pRect->

left,pRect->

top,

hDC,pRect->

top,SRCCOPY);

SelectObject(hMemDC,(HGDIOBJ)hOldBitmap);

DeleteDC(hMemDC);

ReleaseDC(NULL,hDC);

returnhNewBitmap;

下面这两个函数要做的事就差不多了:

OnNcPaint()

CWindowDCdc(CWnd:

FromHandle(m_hWnd));

OnPrint(&

dc);

OnPrint(CDC*pDC)

CRectrc;

GetWindowRect(m_hWnd,&

rc);

rc.OffsetRect(-rc.TopLeft());

//绘制阴影

CDCcMemDC;

cMemDC.CreateCompatibleDC(pDC);

HGDIOBJhOldBitmap=:

SelectObject(cMemDC.m_hDC,m_bmpBack);

pDC->

BitBlt(0,rc.bottom-4,rc.Width()-4,4,&

cMemDC,0,rc.bottom-4,SRCCOPY);

BitBlt(rc.right-4,0,4,rc.Height(),&

cMemDC,rc.right-4,0,SRCCOPY);

DrawShadow(pDC,rc);

rc.right-=4;

rc.bottom-=4;

//绘制边框

Draw3dRect(rc,m_crFrame[0],m_crFrame[1]);

rc.DeflateRect(1,1);

Draw3dRect(rc,m_crFrame[2],m_crFrame[3]);

在指定的矩形区域内绘制阴影的全局函数(当然这些函数不一定都要做成全局函数,我把它们写成了全局函数是因为在好几个类中都用到了它们,写成全局函数便于调用)也许你会觉得这不符合面向对象编程的思想,其实面向过程的编程思想,并不一定就比面向对象的思想落后,我把这些比较独立的函数写成全局函数,当作API函数用,还是觉得很方便的,如果硬要将它们塞到一个类里面,反而觉得很郁闷。

-).voidDrawShadow(CDC*pDC,CRectrect);

voidDrawShadow(CD

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2