【转载】CMenu自绘---钩子---去除边框
? ? ? ?使用默認的CMenu菜單類或者繼承CMenu實現的菜單擴展類,在顯示的時候最外層都會有邊框出現,或者說是具有3D外觀(菜單陰影不算),當改變菜單背景色或者需要加個邊框線時就會看上去很不美觀。看過很多菜單的自定義實現類,一般可以有兩種方式來實現外框的移除。
???????第一種方法就是:自定義窗口,完全模擬菜單的實現,自給自足,倒是能夠完全滿足開發需要,不過實現的復雜讓人頭痛,此處略過不提。
?????? 下面介紹第二種比較簡單直接的方法:安裝鉤子,在菜單創建時就改變其窗口屬性。其實菜單應該也算是一個窗口類,不過實在是無從得知到底在哪創建的窗口,所以下下鉤子,過程倒是明了許多。
?實現如下:
先在cpp前面申明一下:
??????? static HHOOK g_hook=NULL;?// 全局鉤子
??????? static LRESULT WINAPI CallWndProc(int, WPARAM, LPARAM);?// 安裝的鉤子的窗口過程
??????? static LRESULT WINAPI MenuWndProc(HWND, UINT, WPARAM, LPARAM); // 用來處理菜單的窗口過程
然后是鉤子的實現:
/
// 如果需要去除菜單的外部邊框,需要通過安裝鉤子,設置外框屬性并改變菜單大小
WNDPROC oldWndProc = NULL; // 用來保存被替換的窗口過程
LRESULT WINAPI CallWndProc(int code, WPARAM wParam, LPARAM lParam)
{
?CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
?while (code == HC_ACTION)
?{
??HWND hWnd = pStruct->hwnd;
??// 捕捉創建消息WM_CREATE,后面篩選為是否是菜單的創建
??if ( pStruct->message != WM_CREATE)
???break;
??TCHAR sClassName[10];
??int Count = ::GetClassName(hWnd, sClassName, sizeof(sClassName)/sizeof(sClassName[0]));
??// 檢查是否菜單窗口,#32768為菜單類名
??if ( Count != 6 ||? _tcscmp(sClassName, _T("#32768")) != 0 )???
???break;
??
??WNDPROC lastWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);???
??if (lastWndProc != MenuWndProc)???
??{???
???// 替換菜單窗口過程??
???SetWindowLong(hWnd, GWL_WNDPROC, (long)MenuWndProc);???
???// 保留原有的窗口過程???
???oldWndProc = lastWndProc;???
??}
??break;???
?}
?return CallNextHookEx((HHOOK)WH_CALLWNDPROC, code, wParam, lParam);?
}
// 處理菜單的窗口過程
LRESULT WINAPI MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{???
?LRESULT lResult;
?switch (message)???
?{??????
?case WM_CREATE:
??{???
???// 首先要去掉菜單窗口的一些擴展風格
???// 包括:WS_BORDER、WS_EX_DLGMODALFRAME、WS_EX_WINDOWEDGE
???lResult = CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);???
???DWORD dwStyle = ::GetWindowLong(hWnd,?? GWL_STYLE);???
???DWORD dwNewStyle = (dwStyle & ~WS_BORDER);
???::SetWindowLong(hWnd, GWL_STYLE, dwNewStyle);???
???DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
???DWORD dwNewExStyle = (dwExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE));???
???::SetWindowLong(hWnd, GWL_EXSTYLE, dwNewExStyle);???
???return lResult;?
??}???
?case?? WM_PRINT: // 此處阻止非客戶區地繪制
???return CallWindowProc( oldWndProc, hWnd, WM_PRINTCLIENT, wParam, lParam);
?case?? WM_WINDOWPOSCHANGING:???
??{???
???// 最后,由于我們在MeasureItem里指定了菜單大小,而系統會自動替菜單加邊框,
???// 因此必須去掉此部分額外地尺寸,將菜單大小改小
???LPWINDOWPOS lpPos = (LPWINDOWPOS)lParam;???
???lpPos->cx -= 2*GetSystemMetrics(SM_CXBORDER)+4;???
???lpPos->cy -= 2*GetSystemMetrics(SM_CYBORDER)+4;
???lResult = CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);??
???return 0;
??}???
?case?? WM_GETICON:
??return 0;????
?default:???
??return? CallWindowProc( oldWndProc, hWnd, message, wParam, lParam);???
?}???
}??
/
最后是調用:
下鉤子需要調用SetWindowsHookEx,參數包括主窗口的實例句柄theApp.m_hInstance,可以在調用時作為參數傳入,同時也設一個參數作為是否安裝鉤子的標識,以便在退出時判斷是否需要卸載鉤子(UnhookWindowsHookEx(g_hook))。示例如下:
void CSkinMenu::RemoveMenuBorder(HINSTANCE hInst, BOOL bRemove /* = TRUE */)
{
?m_bRemoveBorder = bRemove; // 標識
?// 需要移除邊框時,要安裝鉤子
?if (m_bRemoveBorder)
?{
??DWORD id = ::GetCurrentThreadId();?// 獲取當前線程的ID
??g_hook = SetWindowsHookEx(WH_CALLWNDPROC,CallWndProc,hInst,id);
?}
}
?這樣子,就搞定菜單的邊框了,最后要記得,如果安裝了鉤子,需要卸載掉。
轉載于:https://www.cnblogs.com/doudongchun/p/3699700.html
總結
以上是生活随笔為你收集整理的【转载】CMenu自绘---钩子---去除边框的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个人代码库の全局快捷键
- 下一篇: arcgis server发布地图服务中