VC MFC 钩子 实现 自绘 窗体 标题栏 非客户区(VER.2013-11-06)

【看到网上有很多转载,深感荣幸,今天工作之余在CSDN整理一下】

一. 前言

作者没干过项目,非编程专业人士,仅凭兴趣支撑。所以,程序中一定有很多弱智的段落或者内存泄露之类,所以,这里的文章及代码,只供学习交流之用。其他用途后果自负,所有代码都可无限制免费引用与修改。

原始地址:http://blog.csdn.net/ljfblog/article/details/14224117

转载者请附本节,谢谢。


二. 基本原理:

1.用SetWindowsHookEx截获应用程序级消息。

m_hHook = SetWindowsHookEx(WH_CALLWNDPROC, WindowHook,AfxGetApp()->m_hInstance,GetCurrentThreadId()); 

...

LRESULT CALLBACK CLjfDialog::WindowHook(int code, WPARAM wParam, LPARAM lParam)
{

CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;

//处理截获的消息,本程序中把不同类型窗口分类处理,即CLjfDialog,CLjfButton

}

2.用SetWindowLong(hWnd, GWL_WNDPROC,LjfDialogProc)子类化截获到的窗口。

LRESULT CALLBACK CLjfDialog::LjfDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

//这里就可以截断或处理所有窗口消息了。建议像本代码一样,各自类型的窗口各自处理。

}

3.用CMap或者直接用vector记录已经被子类化的窗口。

4.卸载钩子,释放内存。

三. 核心代码

//安装钩子
void CLjfDialog::Install(CString sSkinIniFileName)
{
    if (m_hHook == NULL )
        m_hHook = SetWindowsHookEx(WH_CALLWNDPROC, 
WindowHook,AfxGetApp()->m_hInstance,GetCurrentThreadId()); 

CLjfIni ini(sSkinIniFileName);
m_sSkinName=ini.GetString("skin","skin","");
if(m_sSkinName == "") m_sSkinName = "skin";//默认
CString sIniPath;sIniPath.Format("%s\\skin.ini",m_sSkinName);
m_sif.GetInfoFromIniFile(sIniPath);

GetCBitmap("bodyfocus",m_cbmpDlgFocus);
GetCBitmap("bodyblur",m_cbmpDlgBlur);
GetCBitmap("sysbtn",m_cbmpSysBtn);
m_sif.PreparBitmapTranRgn(&m_cbmpDlgFocus);
}


//钩子回调消息过程
LRESULT CALLBACK CLjfDialog::WindowHook(int code, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
    if (code == HC_ACTION)
    {
        HWND hWnd = pStruct->hwnd;
        if (pStruct->message != WM_CREATE && pStruct->message != 0x01E2) goto EndProc;


TCHAR strClassName[20];GetClassName (hWnd, strClassName, sizeof(strClassName));
TRACE(strClassName);TRACE("---------\r\n");


//是CDialog类,无标题栏
if (_tcscmp(strClassName, _T("#32770")) == 0 && GetWindowLong(hWnd,GWL_STYLE)&WS_CAPTION)
{
AddSubClass(hWnd,sLjfDialogOldProcTag,(DWORD)(ULONG)LjfDialogProc);
goto EndProc;
}
    }


EndProc:
    return CallNextHookEx (m_hHook, code, wParam, lParam);
}


//子类化
bool CLjfDialog::AddSubClass( HWND &hWnd,TCHAR * oldProcTag,DWORD Proc)
{
if (GetProp(hWnd, oldProcTag) != NULL ) return false;//已被子类化
VERIFY(AddWndHook(hWnd) != NULL);
WNDPROC oldWndProc = (WNDPROC)(long)::GetWindowLong(hWnd, GWL_WNDPROC);// 取原来窗口过程
if (oldWndProc == NULL) return false;
ASSERT((DWORD)(ULONG)oldWndProc != Proc);
if (!SetProp(hWnd, oldProcTag, oldWndProc) ) return false;// 保存到窗口属性
if (!SetWindowLong(hWnd, GWL_WNDPROC,Proc))// 子类化
RemoveProp(hWnd, oldProcTag);
return true;
}

//对话框子类化回调函数
LRESULT CALLBACK CLjfDialog::LjfDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldWndProc = (WNDPROC)GetProp(hWnd, sLjfDialogOldProcTag);
       CLjfDialog* pWnd = GetWndHook(hWnd);
UINT uMsg1=uMsg;
if (pWnd == NULL) goto EndLjfDialogProc;

    switch (uMsg)
    {
case WM_NCCALCSIZE:
return pWnd->OnNcCalcsize(oldWndProc, hWnd, uMsg1, wParam, lParam);
case WM_NCPAINT:
pWnd->OnNcPaint();
return HTNOWHERE;
case WM_SHOWWINDOW:
pWnd->OnShowWindow(wParam != NULL);
break;
case WM_NCDESTROY:
pWnd->OnNcDestroy();
break;
case WM_CREATE:
pWnd->OnCreate((CREATESTRUCT *)lParam);
break;
case WM_NCHITTEST:
return pWnd->OnNcHitTest(oldWndProc, hWnd, uMsg1, wParam, lParam);
case WM_NCACTIVATE:
pWnd->OnNcActivate((BOOL)LOWORD(wParam));
return HTCAPTION;
case 0x00AE://WM_NCUAHDRAWCAPTION 
case 0x00AF://WM_NCUAHDRAWFRAME

//在windows最佳性能时依然在NCBUTTONDOWN和调整大小时有系统最大最小关闭按钮出现,有待解决.
//case WM_NOTIFY:
return HTCAPTION;
case WM_MOVE:
pWnd->OnMove(LOWORD(lParam),HIWORD(lParam));
break;
case WM_NCLBUTTONDOWN:
pWnd->OnNcLButtonDown((UINT)wParam,CPoint(LOWORD(lParam),HIWORD(lParam)));
break;
case WM_NCLBUTTONUP:
pWnd->OnNcLButtonUp((UINT)wParam,CPoint(LOWORD(lParam),HIWORD(lParam)));
break;
case WM_NCMOUSEMOVE:
pWnd->OnNcMouseMove((UINT)wParam,CPoint(LOWORD(lParam),HIWORD(lParam)));
break;
case WM_SIZE:
pWnd->OnSize();
break;
case WM_SETTEXT:
pWnd->OnSetText();
break;
    }
EndLjfDialogProc:
if(IsWindow(hWnd))
return CallWindowProc(oldWndProc, hWnd, uMsg1, wParam, lParam);
else
return HTNOWHERE;
}

四. DEMO下载


http://download.csdn.net/detail/ljfblog/6510269


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ljfblog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值