/*********************************************** * 工作室 : 天光工作室 * 作者 : 张东斌 * 用途 : *************************************************/ #include "StdAfx.h" #include "..\include\Subclass.h" #include "..\include\SkinTools.h" #include "..\include\InitSKinTK.h" extern CInitSKinTK m_skinInit; #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(CSubclassWnd, CWnd); CSubclassWnd::CSubclassWnd() { m_pNext = NULL; m_pOldWndProc = NULL; m_hWnd = NULL; m_bAutoDestroy = TRUE; } CSubclassWnd::~CSubclassWnd() { if (m_hWnd) HookWindow((HWND)NULL); // unhook window } BOOL CSubclassWnd::HookWindow(HWND hwnd) { ASSERT_VALID(this); if (hwnd) { ASSERT(m_hWnd==NULL); ASSERT(::IsWindow(hwnd)); theHookMap.Add(hwnd, this); // Add to map of hooks } else if (m_hWnd) { theHookMap.Remove(this); // Remove from map m_pOldWndProc = NULL; } m_hWnd = hwnd; return TRUE; } LRESULT CSubclassWnd::WindowProc(UINT msg, WPARAM wp, LPARAM lp) { ASSERT(m_pOldWndProc); return m_pNext ? m_pNext->WindowProc(msg, wp, lp) : ::CallWindowProc(m_pOldWndProc, m_hWnd, msg, wp, lp); } LRESULT CSubclassWnd::Default() { MSG& curMsg = AfxGetThreadState()->m_lastSentMsg; return CSubclassWnd::WindowProc(curMsg.message, curMsg.wParam, curMsg.lParam); } LRESULT CSubclassWnd::Default(UINT msg,WPARAM wp, LPARAM lp) { return CSubclassWnd::WindowProc(msg, wp, lp); } /********************************************** * 函数名 : ClientToWindow * 用途 : 客户区坐标转换为窗口坐标 **********************************************/ void CSubclassWnd::ClientToWindow(LPRECT pRect) { ::ClientToScreen(m_hWnd, (LPPOINT)pRect); ::ClientToScreen(m_hWnd, ((LPPOINT)pRect) + 1); ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)pRect, 1); ::MapWindowPoints(NULL, m_hWnd, ((LPPOINT)pRect) + 1, 1); } /********************************************** * 函数名 : ScreenToClient * 用途 : 屏幕坐标转换为客户坐标 **********************************************/ void CSubclassWnd::ScreenToClient(LPRECT pRect) { ::ScreenToClient(m_hWnd, (LPPOINT)pRect); ::ScreenToClient(m_hWnd, ((LPPOINT)pRect) + 1); } /********************************************** * 函数名 : ScreenToClient * 用途 : 客户坐标转换为屏幕坐标 **********************************************/ void CSubclassWnd::ClientToScreen(LPRECT pRect) { ::ClientToScreen(m_hWnd, (LPPOINT)pRect); ::ClientToScreen(m_hWnd, ((LPPOINT)pRect) + 1); } void CSubclassWnd::ClientToScreen(LPPOINT pPoint) { ::ClientToScreen(m_hWnd, pPoint); } #ifdef _DEBUG void CSubclassWnd::AssertValid() const { CObject::AssertValid(); ASSERT(m_hWnd==NULL || ::IsWindow(m_hWnd)); if (m_hWnd) { CSubclassWnd* p = NULL; for (p = theHookMap.Lookup(m_hWnd); p; p=p->m_pNext) { if (p==this) break; } ASSERT(p); // should have found it! } } void CSubclassWnd::Dump(CDumpContext& dc) const { CObject::Dump(dc); } #endif LRESULT CALLBACK HookWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { #ifdef _USRDLL AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif MSG& curMsg = AfxGetThreadState()->m_lastSentMsg; MSG oldMsg = curMsg; curMsg.hwnd = hwnd; curMsg.message = msg; curMsg.wParam = wp; curMsg.lParam = lp; // Get hook object for this window. Get from hook map CSubclassWnd* pSubclassWnd = theHookMap.Lookup(hwnd); ASSERT(pSubclassWnd); LRESULT lr; if (msg==WM_NCDESTROY) { WNDPROC wndproc = pSubclassWnd->m_pOldWndProc; theHookMap.RemoveAll(hwnd); lr = ::CallWindowProc(wndproc, hwnd, msg, wp, lp); } else { lr = pSubclassWnd->WindowProc(msg, wp, lp); } curMsg = oldMsg; // pop state return lr; } CSubclassWndMap::CSubclassWndMap() { } CSubclassWndMap::~CSubclassWndMap() { } CSubclassWndMap& CSubclassWndMap::GetHookMap() { static CSubclassWndMap theMap; return theMap; } void CSubclassWndMap::Add(HWND hwnd, CSubclassWnd* pSubclassWnd) { ASSERT(hwnd && ::IsWindow(hwnd)); // Add to front of list pSubclassWnd->m_pNext = Lookup(hwnd); SetAt(hwnd, pSubclassWnd); if (pSubclassWnd->m_pNext==NULL) { // If this is the first hook added, subclass the window pSubclassWnd->m_pOldWndProc = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)HookWndProc); } else { pSubclassWnd->m_pOldWndProc = pSubclassWnd->m_pNext->m_pOldWndProc; } ASSERT(pSubclassWnd->m_pOldWndProc); } void CSubclassWndMap::Remove(CSubclassWnd* pUnHook) { HWND hwnd = pUnHook->m_hWnd; ASSERT(hwnd && ::IsWindow(hwnd)); CSubclassWnd* pHook = Lookup(hwnd); ASSERT(pHook); if (pHook==pUnHook) { // hook to remove is the one in the hash table: replace w/next if (pHook->m_pNext) SetAt(hwnd, pHook->m_pNext); else { // This is the last hook for this window: restore wnd proc RemoveKey(hwnd); SetWindowLong(hwnd, GWL_WNDPROC, (LONG)pHook->m_pOldWndProc); } } else { // Hook to remove is in the middle: just remove from linked list while (pHook->m_pNext!=pUnHook) pHook = pHook->m_pNext; ASSERT(pHook && pHook->m_pNext==pUnHook); pHook->m_pNext = pUnHook->m_pNext; } } void CSubclassWndMap::RemoveAll(HWND hwnd) { CSubclassWnd* pSubclassWnd; while ((pSubclassWnd = Lookup(hwnd))!=NULL) { pSubclassWnd->HookWindow((HWND)NULL); if(pSubclassWnd->m_bAutoDestroy) delete pSubclassWnd; } } CSubclassWnd* CSubclassWndMap::Lookup(HWND hwnd) { CSubclassWnd* pFound = NULL; if (!CMapPtrToPtr::Lookup(hwnd, (void*&)pFound)) return NULL; ASSERT_KINDOF(CSubclassWnd, pFound); return pFound; }