使用子类化截获窗口消息
在《 多标签视图类CTabView的设计实现》一文中,CTabView从CBasicSubClassWnd私有继承,重写其虚函数SubWindowProc,捕获WM_DRAWITEM和TTN_GETDISPINFO消息,从而实现了DrawItem和UpdateTooltipText虚函数回调机制,支持派生类的自定义处理,而CBasicSubClassWnd就是一个子类化窗口类,其原理很简单,就是挂钩替换目标窗口的消息处理过程,这里的设计实现为对于同一目标窗口,可以被多个CBasicSubClassWnd对象捕获消息,而一个CBasicSubClassWnd对象只能捕获一个目标窗口的消息,SubWindowProc返回值决定了消息是否被传递到下个CBasicSubClassWnd对象或原窗口过程处理,TRUE表示允许消息被传递,否则,反之。CBasicSubClassWnd类基于api + stl实现,简单易用,但不尽完善,比如没考虑支持不同进程间的窗口捕获、类的线程安全性等,这些东西都有待于进一步的解决。下面直接看看它的实现代码
1
//
basic_subclasswnd.h
2 #ifndef _BASIC_SUBCLASSWND_H
3 #define _BASIC_SUBCLASSWND_H
4
5 #include < map >
6 #include < list >
7
8 class CBasicSubClassWnd
9 {
10 friend class CBasicWndInfo;
11
12public:
13 CBasicSubClassWnd();
14 void Hook(HWND hWnd);
15 void Unhook();
16
17protected:
18 virtual BOOL SubWindowProc(UINT msg,WPARAM wParam,LPARAM lParam);
19
20private:
21 HWND m_hWnd;
22} ;
23
24 class CBasicWndInfo
25 {
26 typedef std::list<CBasicSubClassWnd*> CBasicSubClassWndList;
27 friend class CBasicSubClassWnd;
28
29private:
30 CBasicWndInfo(HWND hWnd);
31 void Add(CBasicSubClassWnd* pHandler);
32 void Remove(CBasicSubClassWnd* pHandler);
33 void RemoveAll();
34
35 typedef std::map<HWND,CBasicWndInfo> CBasicSubClassWndMap;
36 typedef CBasicSubClassWndMap::iterator MapIter;
37
38 static CBasicSubClassWndMap& GetHookMap();
39 static LRESULT HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
40
41 CBasicSubClassWndList m_list_scw;
42 WNDPROC m_oldWndProc;
43 HWND m_hWnd;
44} ;
45
46 #endif
47
48 // basic_subclasswnd.cpp
49 #include " stdafx.h "
50 #include " basic_subclasswnd.h "
51 using namespace std;
52
53 CBasicSubClassWnd::CBasicSubClassWnd()
54 :m_hWnd(NULL)
55 {
56}
57
58 void CBasicSubClassWnd::Hook(HWND hWnd)
59 {
60 assert(hWnd);
61 if (m_hWnd&&m_hWnd!=hWnd)
62 Unhook();
63 m_hWnd = hWnd;
64
65 CBasicWndInfo::MapIter iter = CBasicWndInfo::GetHookMap().find(hWnd);
66 if (iter==CBasicWndInfo::GetHookMap().end())
67 {
68 iter = CBasicWndInfo::GetHookMap().insert(make_pair(hWnd,CBasicWndInfo(hWnd))).first;
69 }
70 iter->second.Add(this);
71}
72
73 void CBasicSubClassWnd::Unhook()
74 {
75 assert(m_hWnd);
76
77 CBasicWndInfo::MapIter iter = CBasicWndInfo::GetHookMap().find(m_hWnd);
78 if (iter==CBasicWndInfo::GetHookMap().end())
79 return;
80 iter->second.Remove(this);
81}
82
83 BOOL CBasicSubClassWnd::SubWindowProc(UINT msg,WPARAM wParam,LPARAM lParam)
84 {
85 return TRUE;
86}
87
88 /**/ //////////////////////////////////////////////////////////////////////////////////////////////
89 CBasicWndInfo::CBasicWndInfo(HWND hWnd)
90 :m_oldWndProc(NULL)
91 ,m_hWnd(hWnd)
92 {
93}
94
95 void CBasicWndInfo::Add(CBasicSubClassWnd * pHandler)
96 {
97 if (NULL==m_oldWndProc)
98 {
99 m_oldWndProc = (WNDPROC)SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)HookWndProc);
100 }
101 m_list_scw.push_back(pHandler);
102}
103
104 void CBasicWndInfo::Remove(CBasicSubClassWnd * pHandler)
105 {
106 m_list_scw.remove(pHandler);
107 if (m_list_scw.empty())
108 {
109 assert(m_hWnd);
110 SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)m_oldWndProc);
111 }
112}
113
114 void CBasicWndInfo::RemoveAll()
115 {
116 m_list_scw.clear();
117}
118
119 CBasicWndInfo::CBasicSubClassWndMap & CBasicWndInfo::GetHookMap()
120 {
121 static CBasicSubClassWndMap s_map;
122 return s_map;
123}
124
125 LRESULT CBasicWndInfo::HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
126 {
127 MapIter iter = GetHookMap().find(hWnd);
128 for (CBasicSubClassWndList::iterator it=iter->second.m_list_scw.begin();it!=iter->second.m_list_scw.end();++it)
129 {
130 if (!(*it)->SubWindowProc(uMsg,wParam,lParam))
131 return 0;
132 }
133 return ::CallWindowProc(iter->second.m_oldWndProc,hWnd,uMsg,wParam,lParam);
134}
2 #ifndef _BASIC_SUBCLASSWND_H
3 #define _BASIC_SUBCLASSWND_H
4
5 #include < map >
6 #include < list >
7
8 class CBasicSubClassWnd
9 {
10 friend class CBasicWndInfo;
11
12public:
13 CBasicSubClassWnd();
14 void Hook(HWND hWnd);
15 void Unhook();
16
17protected:
18 virtual BOOL SubWindowProc(UINT msg,WPARAM wParam,LPARAM lParam);
19
20private:
21 HWND m_hWnd;
22} ;
23
24 class CBasicWndInfo
25 {
26 typedef std::list<CBasicSubClassWnd*> CBasicSubClassWndList;
27 friend class CBasicSubClassWnd;
28
29private:
30 CBasicWndInfo(HWND hWnd);
31 void Add(CBasicSubClassWnd* pHandler);
32 void Remove(CBasicSubClassWnd* pHandler);
33 void RemoveAll();
34
35 typedef std::map<HWND,CBasicWndInfo> CBasicSubClassWndMap;
36 typedef CBasicSubClassWndMap::iterator MapIter;
37
38 static CBasicSubClassWndMap& GetHookMap();
39 static LRESULT HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
40
41 CBasicSubClassWndList m_list_scw;
42 WNDPROC m_oldWndProc;
43 HWND m_hWnd;
44} ;
45
46 #endif
47
48 // basic_subclasswnd.cpp
49 #include " stdafx.h "
50 #include " basic_subclasswnd.h "
51 using namespace std;
52
53 CBasicSubClassWnd::CBasicSubClassWnd()
54 :m_hWnd(NULL)
55 {
56}
57
58 void CBasicSubClassWnd::Hook(HWND hWnd)
59 {
60 assert(hWnd);
61 if (m_hWnd&&m_hWnd!=hWnd)
62 Unhook();
63 m_hWnd = hWnd;
64
65 CBasicWndInfo::MapIter iter = CBasicWndInfo::GetHookMap().find(hWnd);
66 if (iter==CBasicWndInfo::GetHookMap().end())
67 {
68 iter = CBasicWndInfo::GetHookMap().insert(make_pair(hWnd,CBasicWndInfo(hWnd))).first;
69 }
70 iter->second.Add(this);
71}
72
73 void CBasicSubClassWnd::Unhook()
74 {
75 assert(m_hWnd);
76
77 CBasicWndInfo::MapIter iter = CBasicWndInfo::GetHookMap().find(m_hWnd);
78 if (iter==CBasicWndInfo::GetHookMap().end())
79 return;
80 iter->second.Remove(this);
81}
82
83 BOOL CBasicSubClassWnd::SubWindowProc(UINT msg,WPARAM wParam,LPARAM lParam)
84 {
85 return TRUE;
86}
87
88 /**/ //////////////////////////////////////////////////////////////////////////////////////////////
89 CBasicWndInfo::CBasicWndInfo(HWND hWnd)
90 :m_oldWndProc(NULL)
91 ,m_hWnd(hWnd)
92 {
93}
94
95 void CBasicWndInfo::Add(CBasicSubClassWnd * pHandler)
96 {
97 if (NULL==m_oldWndProc)
98 {
99 m_oldWndProc = (WNDPROC)SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)HookWndProc);
100 }
101 m_list_scw.push_back(pHandler);
102}
103
104 void CBasicWndInfo::Remove(CBasicSubClassWnd * pHandler)
105 {
106 m_list_scw.remove(pHandler);
107 if (m_list_scw.empty())
108 {
109 assert(m_hWnd);
110 SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)m_oldWndProc);
111 }
112}
113
114 void CBasicWndInfo::RemoveAll()
115 {
116 m_list_scw.clear();
117}
118
119 CBasicWndInfo::CBasicSubClassWndMap & CBasicWndInfo::GetHookMap()
120 {
121 static CBasicSubClassWndMap s_map;
122 return s_map;
123}
124
125 LRESULT CBasicWndInfo::HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
126 {
127 MapIter iter = GetHookMap().find(hWnd);
128 for (CBasicSubClassWndList::iterator it=iter->second.m_list_scw.begin();it!=iter->second.m_list_scw.end();++it)
129 {
130 if (!(*it)->SubWindowProc(uMsg,wParam,lParam))
131 return 0;
132 }
133 return ::CallWindowProc(iter->second.m_oldWndProc,hWnd,uMsg,wParam,lParam);
134}