在《多標簽視圖類CTabView的設計實現》:http://www.BkJia.com/kf/201112/113805.html 一文中,CTabView從CBasicSubClassWnd私有繼承,重寫其虛函數SubWindowProc,捕獲WM_DRAWITEM和TTN_GETDISPINFO消息,從而實現了DrawItem和UpdateTooltipText虛函數回調機制,支持派生類的自定義處理,而CBasicSubClassWnd就是一個子類化窗口類,其原理很簡單,就是掛鉤替換目標窗口的消息處理過程,這裡的設計實現為對於同一目標窗口,可以被多個CBasicSubClassWnd對象捕獲消息,而一個CBasicSubClassWnd對象只能捕獲一個目標窗口的消息,SubWindowProc返回值決定了消息是否被傳遞到下個CBasicSubClassWnd對象或原窗口過程處理,TRUE表示允許消息被傳遞,否則,反之。CBasicSubClassWnd類基於api + stl實現,簡單易用,但不盡完善,比如沒考慮支持不同進程間的窗口捕獲、類的線程安全性等,這些東西都有待於進一步的解決。下面直接看看它的實現代碼
1//basic_subclasswnd.h
2
3#ifndef _BASIC_SUBCLASSWND_H
4#define _BASIC_SUBCLASSWND_H
5
6#include <map>
7#include <list>
8
9class CBasicSubClassWnd
10{
11 friend class CBasicWndInfo;
12
13public:
14 CBasicSubClassWnd();
15 void Hook(HWND hWnd);
16 void Unhook();
17
18protected:
19 virtual BOOL SubWindowProc(UINT msg,WPARAM wParam,LPARAM lParam);
20
21private:
22 HWND m_hWnd;
23};
24
25class CBasicWndInfo
26{
27 typedef std::list<CBasicSubClassWnd*> CBasicSubClassWndList;
28 friend class CBasicSubClassWnd;
29
30private:
31 CBasicWndInfo(HWND hWnd);
32 void Add(CBasicSubClassWnd* pHandler);
33 void Remove(CBasicSubClassWnd* pHandler);
34 void RemoveAll();
35
36 typedef std::map<HWND,CBasicWndInfo> CBasicSubClassWndMap;
37 typedef CBasicSubClassWndMap::iterator MapIter;
38
39 static CBasicSubClassWndMap& GetHookMap();
40 static LRESULT HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
41
42 CBasicSubClassWndList m_list_scw;
43 WNDPROC m_oldWndProc;
44 HWND m_hWnd;
45};
46
47#endif
48
49//basic_subclasswnd.cpp
50#include "stdafx.h"
51#include "basic_subclasswnd.h"
52using namespace std;
53
54CBasicSubClassWnd::CBasicSubClassWnd()
55:m_hWnd(NULL)
56{
57}
58
59void CBasicSubClassWnd::Hook(HWND hWnd)
60{
61 assert(hWnd);
62 if (m_hWnd&&m_hWnd!=hWnd)
63 Unhook();
64 m_hWnd = hWnd;
65
66 CBasicWndInfo::MapIter iter = CBasicWndInfo::GetHookMap().find(hWnd);
67 if (iter==CBasicWndInfo::GetHookMap().end())
68 {
69 iter = CBasicWndInfo::GetHookMap().insert(make_pair(hWnd,CBasicWndInfo(hWnd))).first;
70 }
71 iter->second.Add(this);
72}
73
74void CBasicSubClassWnd::Unhook()
75{
76 assert(m_hWnd);
77
78 CBasicWndInfo::MapIter iter = CBasicWndInfo::GetHookMap().find(m_hWnd);
79 if (iter==CBasicWndInfo::GetHookMap().end())
80 return;
81 iter->second.Remove(this);
82}
83
84BOOL CBasicSubClassWnd::SubWindowProc(UINT msg,WPARAM wParam,LPARAM lParam)
85{
86 return TRUE;
87}
88
89//////////////////////////////////////////////////////////////////////////////////////////////
90CBasicWndInfo::CBasicWndInfo(HWND hWnd)
91:m_oldWndProc(NULL)
92,m_hWnd(hWnd)
93{
94}
95
96void CBasicWndInfo::Add(CBasicSubClassWnd* pHandler)
97{
98 if (NULL==m_oldWndProc)
99 {
100 m_oldWndProc = (WNDPROC)SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)HookWndProc);
101 }
102 m_list_scw.push_back(pHandler);
103}
104
105void CBasicWndInfo::Remove(CBasicSubClassWnd* pHandler)
106{
107 m_list_scw.remove(pHandler);
108 if (m_list_scw.empty())
109 {
110 assert(m_hWnd);
111 SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)m_oldWndProc);
112 }
113}
114
115void CBasicWndInfo::RemoveAll()
116{
117 m_list_scw.clear();
118}
119
120CBasicWndInfo::CBasicSubClassWndMap& CBasicWndInfo::GetHookMap()
121{
122 static CBasicSubClassWndMap s_map;
123 return s_map;
124}
125
126LRESULT CBasicWndInfo::HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
127{
128 MapIter iter = GetHookMap().find(hWnd);
129 if (uMsg==WM_NCDESTROY)
130 {
131 //iter->second.RemoveAll();
132 }
133 else
134 {
135 CBasicSubClassWndList::iterator it;
136 for (it=iter->second.m_list_scw.begin();it!=iter->second.m_list_scw.end();++it)
137 {
138 if (!(*it)->SubWindowProc(uMsg,wParam,lParam))
139 return 0;
140 }
141 }
142 return ::CallWindowProc(iter->second.m_oldWndProc,hWnd,uMsg,wParam,lParam);
143}
摘自 天道酬勤