Subclass.cpp
上传用户:zhanglf88
上传日期:2013-11-19
资源大小:6036k
文件大小:8k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------//
  2. // This is a part of the GuiLib MFC Extention.  //
  3. // Modified by  :  Francisco Campos  //
  4. // (C) 2002 Francisco Campos <www.beyondata.com> All rights reserved     //
  5. // This code is provided "as is", with absolutely no warranty expressed  //
  6. // or implied. Any use is at your own risk.  //
  7. // You must obtain the author's consent before you can include this code //
  8. // in a software library.  //
  9. // If the source code in  this file is used in any application  //
  10. // then acknowledgement must be made to the author of this program  //
  11. // fcampos@tutopia.com  //
  12. //-----------------------------------------------------------------------//
  13. ////////////////////////////////////////////////////////////////
  14. // PixieLib(TM) Copyright 1997-1998 Paul DiLascia
  15. // If this code works, it was written by Paul DiLascia.
  16. // If not, I don't know who wrote it.
  17. //
  18. // CSubclassWnd is a generic class for hooking another window's messages.
  19. #include "stdafx.h"
  20. #include "Subclass.h"
  21. #ifdef _DEBUG
  22. #define new DEBUG_NEW
  23. #undef THIS_FILE
  24. static char THIS_FILE[] = __FILE__;
  25. #endif
  26. //////////////////
  27. // The message hook map is derived from CMapPtrToPtr, which associates
  28. // a pointer with another pointer. It maps an HWND to a CSubclassWnd, like
  29. // the way MFC's internal maps map HWND's to CWnd's. The first CSubclassWnd
  30. // attached to a window is stored in the map; all other CSubclassWnd's for that
  31. // window are then chained via CSubclassWnd::m_pNext.
  32. //
  33. class CSubclassWndMap : private CMapPtrToPtr {
  34. public:
  35. CSubclassWndMap();
  36. ~CSubclassWndMap();
  37. static CSubclassWndMap& GetHookMap();
  38. void Add(HWND hwnd, CSubclassWnd* pSubclassWnd);
  39. void Remove(CSubclassWnd* pSubclassWnd);
  40. void RemoveAll(HWND hwnd);
  41. CSubclassWnd* Lookup(HWND hwnd);
  42. };
  43. // This trick is used so the hook map isn't
  44. // instantiated until someone actually requests it.
  45. //
  46. #define theHookMap (CSubclassWndMap::GetHookMap())
  47. IMPLEMENT_DYNAMIC(CSubclassWnd, CWnd);
  48. CSubclassWnd::CSubclassWnd()
  49. {
  50. m_pNext = NULL;
  51. m_pOldWndProc = NULL;
  52. m_hWnd  = NULL;
  53. }
  54. CSubclassWnd::~CSubclassWnd()
  55. {
  56. if (m_hWnd) 
  57. HookWindow((HWND)NULL); // unhook window
  58. }
  59. //////////////////
  60. // Hook a window.
  61. // This installs a new window proc that directs messages to the CSubclassWnd.
  62. // pWnd=NULL to remove.
  63. //
  64. BOOL CSubclassWnd::HookWindow(HWND hwnd)
  65. {
  66. ASSERT_VALID(this);
  67. if (hwnd) {
  68. // Hook the window
  69. ASSERT(m_hWnd==NULL);
  70. ASSERT(::IsWindow(hwnd));
  71. theHookMap.Add(hwnd, this); // Add to map of hooks
  72. } else if (m_hWnd) {
  73. // Unhook the window
  74. theHookMap.Remove(this); // Remove from map
  75. m_pOldWndProc = NULL;
  76. }
  77. m_hWnd = hwnd;
  78. return TRUE;
  79. }
  80. //////////////////
  81. // Window proc-like virtual function which specific CSubclassWnds will
  82. // override to do stuff. Default passes the message to the next hook; 
  83. // the last hook passes the message to the original window.
  84. // You MUST call this at the end of your WindowProc if you want the real
  85. // window to get the message. This is just like CWnd::WindowProc, except that
  86. // a CSubclassWnd is not a window.
  87. //
  88. LRESULT CSubclassWnd::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
  89. {
  90. // ASSERT_VALID(this);  // removed for speed
  91. ASSERT(m_pOldWndProc);
  92. return m_pNext ? m_pNext->WindowProc(msg, wp, lp) :
  93. ::CallWindowProc(m_pOldWndProc, m_hWnd, msg, wp, lp);
  94. }
  95. //////////////////
  96. // Like calling base class WindowProc, but with no args, so individual
  97. // message handlers can do the default thing. Like CWnd::Default
  98. //
  99. LRESULT CSubclassWnd::Default()
  100. {
  101. // MFC stores current MSG in thread state
  102. MSG& curMsg = AfxGetThreadState()->m_lastSentMsg;
  103. // Note: must explicitly call CSubclassWnd::WindowProc to avoid infinte
  104. // recursion on virtual function
  105. return CSubclassWnd::WindowProc(curMsg.message, curMsg.wParam, curMsg.lParam);
  106. }
  107. #ifdef _DEBUG
  108. void CSubclassWnd::AssertValid() const
  109. {
  110. CObject::AssertValid();
  111. ASSERT(m_hWnd==NULL || ::IsWindow(m_hWnd));
  112. if (m_hWnd) {
  113. for (CSubclassWnd* p = theHookMap.Lookup(m_hWnd); p; p=p->m_pNext) {
  114. if (p==this)
  115. break;
  116. }
  117. ASSERT(p); // should have found it!
  118. }
  119. }
  120. void CSubclassWnd::Dump(CDumpContext& dc) const
  121. {
  122. CObject::Dump(dc);
  123. }
  124. #endif
  125. //////////////////
  126. // Subclassed window proc for message hooks. Replaces AfxWndProc (or whatever
  127. // else was there before.)
  128. //
  129. LRESULT CALLBACK
  130. HookWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
  131. {
  132. #ifdef _USRDLL
  133. // If this is a DLL, need to set up MFC state
  134. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  135. #endif
  136. // Set up MFC message state just in case anyone wants it
  137. // This is just like AfxCallWindowProc, but we can't use that because
  138. // a CSubclassWnd is not a CWnd.
  139. //
  140. MSG& curMsg = AfxGetThreadState()->m_lastSentMsg;
  141. MSG  oldMsg = curMsg;   // save for nesting
  142. curMsg.hwnd = hwnd;
  143. curMsg.message = msg;
  144. curMsg.wParam  = wp;
  145. curMsg.lParam  = lp;
  146. // Get hook object for this window. Get from hook map
  147. CSubclassWnd* pSubclassWnd = theHookMap.Lookup(hwnd);
  148. ASSERT(pSubclassWnd);
  149. LRESULT lr;
  150. if (msg==WM_NCDESTROY) {
  151. // Window is being destroyed: unhook all hooks (for this window)
  152. // and pass msg to orginal window proc
  153. //
  154. WNDPROC wndproc = pSubclassWnd->m_pOldWndProc;
  155. theHookMap.RemoveAll(hwnd);
  156. lr = ::CallWindowProc(wndproc, hwnd, msg, wp, lp);
  157. } else {
  158. // pass to msg hook
  159. lr = pSubclassWnd->WindowProc(msg, wp, lp);
  160. }
  161. curMsg = oldMsg; // pop state
  162. return lr;
  163. }
  164. ////////////////////////////////////////////////////////////////
  165. // CSubclassWndMap implementation
  166. //
  167. CSubclassWndMap::CSubclassWndMap()
  168. {
  169. }
  170. CSubclassWndMap::~CSubclassWndMap()
  171. {
  172. // This assert bombs when posting WM_QUIT, so I've deleted it.
  173. // ASSERT(IsEmpty()); // all hooks should be removed!
  174. }
  175. //////////////////
  176. // Get the one and only global hook map
  177. // 
  178. CSubclassWndMap& CSubclassWndMap::GetHookMap()
  179. {
  180. // By creating theMap here, C++ doesn't instantiate it until/unless
  181. // it's ever used! This is a good trick to use in C++, to
  182. // instantiate/initialize a static object the first time it's used.
  183. //
  184. static CSubclassWndMap theMap;
  185. return theMap;
  186. }
  187. /////////////////
  188. // Add hook to map; i.e., associate hook with window
  189. //
  190. void CSubclassWndMap::Add(HWND hwnd, CSubclassWnd* pSubclassWnd)
  191. {
  192. ASSERT(hwnd && ::IsWindow(hwnd));
  193. // Add to front of list
  194. pSubclassWnd->m_pNext = Lookup(hwnd);
  195. SetAt(hwnd, pSubclassWnd);
  196. if (pSubclassWnd->m_pNext==NULL) {
  197. // If this is the first hook added, subclass the window
  198. pSubclassWnd->m_pOldWndProc = 
  199. (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)HookWndProc);
  200. } else {
  201. // just copy wndproc from next hook
  202. pSubclassWnd->m_pOldWndProc = pSubclassWnd->m_pNext->m_pOldWndProc;
  203. }
  204. ASSERT(pSubclassWnd->m_pOldWndProc);
  205. }
  206. //////////////////
  207. // Remove hook from map
  208. //
  209. void CSubclassWndMap::Remove(CSubclassWnd* pUnHook)
  210. {
  211. HWND hwnd = pUnHook->m_hWnd;
  212. ASSERT(hwnd && ::IsWindow(hwnd));
  213. CSubclassWnd* pHook = Lookup(hwnd);
  214. ASSERT(pHook);
  215. if (pHook==pUnHook) {
  216. // hook to remove is the one in the hash table: replace w/next
  217. if (pHook->m_pNext)
  218. SetAt(hwnd, pHook->m_pNext);
  219. else {
  220. // This is the last hook for this window: restore wnd proc
  221. RemoveKey(hwnd);
  222. SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)pHook->m_pOldWndProc);
  223. }
  224. } else {
  225. // Hook to remove is in the middle: just remove from linked list
  226. while (pHook->m_pNext!=pUnHook)
  227. pHook = pHook->m_pNext;
  228. ASSERT(pHook && pHook->m_pNext==pUnHook);
  229. pHook->m_pNext = pUnHook->m_pNext;
  230. }
  231. }
  232. //////////////////
  233. // Remove all the hooks for a window
  234. //
  235. void CSubclassWndMap::RemoveAll(HWND hwnd)
  236. {
  237. CSubclassWnd* pSubclassWnd;
  238. while ((pSubclassWnd = Lookup(hwnd))!=NULL)
  239. pSubclassWnd->HookWindow((HWND)NULL); // (unhook)
  240. }
  241. /////////////////
  242. // Find first hook associate with window
  243. //
  244. CSubclassWnd* CSubclassWndMap::Lookup(HWND hwnd)
  245. {
  246. CSubclassWnd* pFound = NULL;
  247. if (!CMapPtrToPtr::Lookup(hwnd, (void*&)pFound))
  248. return NULL;
  249. ASSERT_KINDOF(CSubclassWnd, pFound);
  250. return pFound;
  251. }