📄 rtmenu.cpp
字号:
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// CRTWndMenu class : management of the window used by system to display popup menus
//
class CRTWndMenu
{
public:
CRTWndMenu (HWND hWnd);
~CRTWndMenu ();
public:
static CRTWndMenu* FromHandle (HWND hWnd, bool bPermanent = true);
protected:
void OnWindowPosChanging (WINDOWPOS* pWP);
void OnEraseBkgnd ();
void OnPrint (CDC* pDC, bool bOwnerDrawnItems);
void OnNcPaint ();
void OnShowWindow (bool bShow);
void OnNcDestroy ();
private:
static LRESULT CALLBACK WindowsHook (int code, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK SubClassMenuProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
HWND m_hWnd;
CRect m_rcMenu;
CPoint m_ptMenu;
CBitmap m_bmpBkGnd;
static CMap <HWND, HWND, CRTWndMenu*, CRTWndMenu*> ms_WndMenuMap;
static DWORD ms_dwRefCount;
static HHOOK ms_hHookOldMenuCbtFilter;
friend class CRTMenu;
};
///////////////////////////////////////////////////////////////////////////////
void CRTMenu::InitializeHook ()
{
CRTWndMenu::ms_dwRefCount++;
if ( CRTWndMenu::ms_hHookOldMenuCbtFilter == NULL )
{
CRTWndMenu::ms_hHookOldMenuCbtFilter = ::SetWindowsHookEx (WH_CALLWNDPROC, CRTWndMenu::WindowsHook, AfxGetApp()->m_hInstance, ::GetCurrentThreadId());
}
}
///////////////////////////////////////////////////////////////////////////////
void CRTMenu::UninitializeHook ()
{
if ( CRTWndMenu::ms_dwRefCount == 0 )
{
return;
}
if ( --CRTWndMenu::ms_dwRefCount == 0 )
{
POSITION pos = CRTWndMenu::ms_WndMenuMap.GetStartPosition();
while ( pos != NULL )
{
HWND hKey;
CRTWndMenu* pVal;
CRTWndMenu::ms_WndMenuMap.GetNextAssoc (pos, hKey, pVal);
delete pVal;
}
CRTWndMenu::ms_WndMenuMap.RemoveAll();
if ( CRTWndMenu::ms_hHookOldMenuCbtFilter != NULL )
{
::UnhookWindowsHookEx (CRTWndMenu::ms_hHookOldMenuCbtFilter);
}
}
}
///////////////////////////////////////////////////////////////////////////////
CMap <HWND, HWND, CRTWndMenu*, CRTWndMenu*> CRTWndMenu::ms_WndMenuMap;
DWORD CRTWndMenu::ms_dwRefCount = 0;
HHOOK CRTWndMenu::ms_hHookOldMenuCbtFilter = NULL;
///////////////////////////////////////////////////////////////////////////////
CRTWndMenu::CRTWndMenu (HWND hWnd)
: m_hWnd (hWnd), m_rcMenu (0, 0, 0, 0), m_ptMenu (-0xFFFF, -0xFFFF)
{
}
///////////////////////////////////////////////////////////////////////////////
CRTWndMenu::~CRTWndMenu ()
{
WNDPROC oldWndProc = (WNDPROC)::GetProp (m_hWnd, _WndPropName_OldProc);
if ( oldWndProc != NULL )
{
::SetWindowLong (m_hWnd, GWL_WNDPROC, (DWORD)(DWORD_PTR)oldWndProc);
::RemoveProp (m_hWnd, _WndPropName_OldProc);
}
ms_WndMenuMap.RemoveKey (m_hWnd);
}
///////////////////////////////////////////////////////////////////////////////
CRTWndMenu* CRTWndMenu::FromHandle (HWND hWnd, bool bPermanent)
{
CRTWndMenu* pWnd = NULL;
if ( ms_WndMenuMap.Lookup (hWnd, pWnd) )
{
return pWnd;
}
if ( bPermanent )
{
return NULL;
}
pWnd = new CRTWndMenu (hWnd);
ms_WndMenuMap.SetAt (hWnd, pWnd);
return pWnd;
}
///////////////////////////////////////////////////////////////////////////////
void CRTWndMenu::OnWindowPosChanging (WINDOWPOS* pWP)
{
if ( GetWinVersion() < wvWinXP )
{
pWP->cx += SM_CXSHADOW;
pWP->cy += SM_CXSHADOW;
}
pWP->y--;
m_ptMenu.x = pWP->x;
m_ptMenu.y = pWP->y;
}
///////////////////////////////////////////////////////////////////////////////
void CRTWndMenu::OnEraseBkgnd ()
{
if ( !IsWindowVisible (m_hWnd) )
{
CClientRect rc (m_hWnd);
if ( m_bmpBkGnd.m_hObject != NULL )
{
m_bmpBkGnd.DeleteObject();
}
m_bmpBkGnd.Attach (GetScreenBitmap (CRect (m_ptMenu.x, m_ptMenu.y, rc.right+m_ptMenu.x+10,
rc.bottom+m_ptMenu.y+10)));
}
}
///////////////////////////////////////////////////////////////////////////////
void DrawShadow (HDC hDCIn, HDC hDCOut, RECT& rc)
{
for ( int x = 0; x < rc.right-1; x++ )
{
int nEnd = ( x > rc.right-SM_CXSHADOW*2 ) ? rc.right-SM_CXSHADOW-x : SM_CXSHADOW;
for ( int y = ( x < 2 ) ? 2-x : x > rc.right-SM_CXSHADOW-3 ? x-rc.right+SM_CXSHADOW+3 : 0; y < nEnd; y++ )
{
int nMakeSpec = 78+(3-(x==0?0:(x==1?(y<2?0:1):(x==2?(y<2?y:2):y))))*5;
COLORREF cr = GetPixel (hDCIn, x+SM_CXSHADOW, rc.bottom-y-1);
COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
((nMakeSpec * int(GetGValue(cr))) / 100),
((nMakeSpec * int(GetBValue(cr))) / 100));
SetPixel (hDCOut, x+SM_CXSHADOW, rc.bottom-y-1, cr2);
}
}
for ( x = 0; x < SM_CXSHADOW; x++ )
{
for ( int y = ( x < 2 ) ? 2-x : 0; y < rc.bottom-x-SM_CXSHADOW-((x>0)?1:2); y++ )
{
int nMakeSpec = 78+(3-(y==0?0:(y==1?(x<2?0:1):(y==2?(x<2?x:2):x))))*5;
COLORREF cr = GetPixel (hDCIn, rc.right-x-1, y+SM_CXSHADOW);
COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
((nMakeSpec * int(GetGValue(cr))) / 100),
((nMakeSpec * int(GetBValue(cr))) / 100));
SetPixel (hDCOut, rc.right-x-1, y+SM_CXSHADOW, cr2);
}
}
}
///////////////////////////////////////////////////////////////////////////////
void CRTWndMenu::OnPrint (CDC* pDC, bool bOwnerDrawnItems)
{
CWindowRect rc (m_hWnd);
CBrushDC br (pDC->m_hDC);
CPenDC pen (pDC->m_hDC, ::GetSysColor (COLOR_3DDKSHADOW));
rc.OffsetRect (-rc.TopLeft());
m_rcMenu = rc;
if ( GetWinVersion() < wvWinXP )
{
rc.right -= SM_CXSHADOW;
rc.bottom -= SM_CXSHADOW;
}
pDC->Rectangle (rc);
pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
rc.DeflateRect (1, 1);
pDC->Rectangle (rc);
rc.DeflateRect (1, 1);
pDC->Rectangle (rc);
if ( bOwnerDrawnItems && !CRTMenuItem::ms_rcMRUMenuBarItem.IsRectEmpty() &&
CRTMenuItem::ms_rcMRUMenuBarItem.bottom == m_ptMenu.y+1 )
{
pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
pDC->MoveTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x-3, 0);
pDC->LineTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x+CRTMenuItem::ms_rcMRUMenuBarItem.Width()-5, 0);
}
if ( GetWinVersion() < wvWinXP )
{
rc.right += SM_CXSHADOW+2;
rc.bottom += SM_CXSHADOW+2;
CDC cMemDC;
cMemDC.CreateCompatibleDC (pDC);
HGDIOBJ hOldBitmap = ::SelectObject (cMemDC.m_hDC, m_bmpBkGnd);
pDC->BitBlt (0, rc.bottom-SM_CXSHADOW, SM_CXSHADOW*2, SM_CXSHADOW, &cMemDC, 0, rc.bottom-SM_CXSHADOW, SRCCOPY);
pDC->BitBlt (rc.right-SM_CXSHADOW, rc.bottom-SM_CXSHADOW, SM_CXSHADOW, SM_CXSHADOW, &cMemDC, rc.right-SM_CXSHADOW, rc.bottom-SM_CXSHADOW, SRCCOPY);
pDC->BitBlt (rc.right-SM_CXSHADOW, 0, SM_CXSHADOW, SM_CXSHADOW*2, &cMemDC, rc.right-SM_CXSHADOW, 0, SRCCOPY);
DrawShadow (cMemDC.m_hDC, pDC->m_hDC, rc);
::SelectObject (cMemDC.m_hDC, hOldBitmap);
}
}
///////////////////////////////////////////////////////////////////////////////
void CRTWndMenu::OnNcPaint ()
{
CWindowDC cDC (CWnd::FromHandle (m_hWnd));
CDC* pDC = &cDC;
CWindowRect rc (m_hWnd);
m_ptMenu.x = rc.left;
m_ptMenu.y = rc.top;
rc.OffsetRect (-rc.TopLeft());
if ( rc != m_rcMenu )
{
m_rcMenu = rc;
CBrushDC br (pDC->m_hDC);
CPenDC pen (pDC->m_hDC, ::GetSysColor (COLOR_3DDKSHADOW));
if ( GetWinVersion() < wvWinXP )
{
rc.right -= SM_CXSHADOW;
rc.bottom -= SM_CXSHADOW;
}
pDC->Rectangle (rc);
pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
rc.DeflateRect (1, 1);
pDC->Rectangle (rc);
rc.DeflateRect (1, 1);
pDC->Rectangle (rc);
if ( !CRTMenuItem::ms_rcMRUMenuBarItem.IsRectEmpty() &&
CRTMenuItem::ms_rcMRUMenuBarItem.bottom == m_ptMenu.y+1 )
{
pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
pDC->MoveTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x-3, 0);
pDC->LineTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x+CRTMenuItem::ms_rcMRUMenuBarItem.Width()-5, 0);
}
if ( GetWinVersion() < wvWinXP )
{
rc.right += SM_CXSHADOW+2;
rc.bottom += SM_CXSHADOW+2;
DrawShadow (pDC->m_hDC, pDC->m_hDC, rc);
}
}
}
///////////////////////////////////////////////////////////////////////////////
void CRTWndMenu::OnShowWindow (bool bShow)
{
if ( !bShow )
{
delete this;
}
}
///////////////////////////////////////////////////////////////////////////////
void CRTWndMenu::OnNcDestroy ()
{
delete this;
}
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK CRTWndMenu::WindowsHook (int code, WPARAM wParam, LPARAM lParam)
{
CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
// Not a real loop (just for 'break' branchment)
while ( code == HC_ACTION )
{
HWND hWnd = pStruct->hwnd;
// Normal and special handling for menu 0x10012
if ( pStruct->message != WM_CREATE && pStruct->message != 0x01E2 )
{
break;
}
CWnd* pFrame = CWnd::GetForegroundWindow();
if ( pFrame == NULL || !CRTMenu::GetXPLookNFeel (pFrame) || !CRTMenu::m_bEnableSkin )
{
break;
}
TCHAR sClassName[10];
int Count = ::GetClassName (hWnd, sClassName, lengthof(sClassName));
// Check for the menu-class
if ( Count != 6 || _tcscmp (sClassName, _T("#32768")) != 0 )
{
break;
}
VERIFY(CRTWndMenu::FromHandle (pStruct->hwnd, false) != NULL);
if ( ::GetProp (pStruct->hwnd, _WndPropName_OldProc) != NULL )
{
// Already subclassed
break;
}
// Subclass the window
WNDPROC oldWndProc = (WNDPROC)(LONG_PTR)::GetWindowLong (pStruct->hwnd, GWL_WNDPROC);
if ( oldWndProc == NULL )
{
break;
}
ASSERT(oldWndProc != SubClassMenuProc);
if ( !SetProp (pStruct->hwnd, _WndPropName_OldProc, oldWndProc) )
{
break;
}
if ( !SetWindowLong (pStruct->hwnd, GWL_WNDPROC,(DWORD)(DWORD_PTR)SubClassMenuProc) )
{
::RemoveProp (pStruct->hwnd, _WndPropName_OldProc);
break;
}
// Success !
break;
}
return CallNextHookEx (CRTWndMenu::ms_hHookOldMenuCbtFilter, code, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK CRTWndMenu::SubClassMenuProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldWndProc = (WNDPROC)::GetProp (hWnd, _WndPropName_OldProc);
CRTWndMenu* pWnd = NULL;
switch ( uMsg )
{
case WM_NCCALCSIZE:
{
LRESULT lResult = CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
if ( GetWinVersion() < wvWinXP )
{
NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)lParam;
lpncsp->rgrc[0].right -= SM_CXSHADOW;
lpncsp->rgrc[0].bottom -= SM_CXSHADOW;
}
return lResult;
}
case WM_WINDOWPOSCHANGING:
if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
{
pWnd->OnWindowPosChanging ((LPWINDOWPOS)lParam);
}
break;
case WM_ERASEBKGND:
if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
{
pWnd->OnEraseBkgnd();
}
break;
case WM_PRINT:
{
BYTE nCheck = CRTMenuItem::ms_nCheck;
LRESULT lResult = CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
bool bOwnerDrawnItems = nCheck != CRTMenuItem::ms_nCheck;
if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
{
pWnd->OnPrint (CDC::FromHandle ((HDC)wParam), bOwnerDrawnItems);
}
return lResult;
}
case WM_NCPAINT:
if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
{
pWnd->OnNcPaint();
return 0;
}
break;
case WM_SHOWWINDOW:
if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
{
pWnd->OnShowWindow (wParam != 0);
}
break;
case WM_NCDESTROY:
if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
{
pWnd->OnNcDestroy();
}
break;
}
return CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -