Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
8.7 KiB

  1. #include "stdafx.h"
  2. #include "Lava.h"
  3. #include "HWndHelp.h"
  4. /***************************************************************************\
  5. *****************************************************************************
  6. *
  7. * WindowProc thunks provide a mechanism of attaching a new WNDPROC to an
  8. * existing HWND. This does not require you to derive from any classes,
  9. * does not use any HWND properties, and can be applied multiple times on the
  10. * same HWND.
  11. *
  12. * Taken from ATLWIN.H
  13. *
  14. *****************************************************************************
  15. \***************************************************************************/
  16. /////////////////////////////////////////////////////////////////////////////
  17. // WindowProc thunks
  18. class CWndProcThunk
  19. {
  20. public:
  21. _AtlCreateWndData cd;
  22. CStdCallThunk thunk;
  23. void Init(WNDPROC proc, void* pThis)
  24. {
  25. thunk.Init((DWORD_PTR)proc, pThis);
  26. }
  27. };
  28. #define DUSERUNSUBCLASSMESSAGE "DUserUnSubClassMessage"
  29. class WndBridge
  30. {
  31. // Construction
  32. public:
  33. WndBridge();
  34. ~WndBridge();
  35. static HRESULT Build(HWND hwnd, ATTACHWNDPROC pfnDelegate, void * pvDelegate, BOOL fAnsi);
  36. HRESULT Detach(BOOL fForceCleanup);
  37. // Operations
  38. public:
  39. static LRESULT CALLBACK
  40. RawWndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
  41. // Data
  42. protected:
  43. CWndProcThunk m_thunkUs;
  44. ATTACHWNDPROC m_pfnDelegate;
  45. void * m_pvDelegate;
  46. HWND m_hwnd;
  47. WNDPROC m_pfnOldWndProc;
  48. BOOL m_fAnsi;
  49. UINT m_msgUnSubClass;
  50. private:
  51. ULONG AddRef();
  52. ULONG Release();
  53. LONG m_cRefs;
  54. BOOL m_fAttached;
  55. };
  56. //------------------------------------------------------------------------------
  57. WndBridge::WndBridge()
  58. {
  59. m_thunkUs.Init(RawWndProc, this);
  60. m_msgUnSubClass = RegisterWindowMessage(DUSERUNSUBCLASSMESSAGE);
  61. m_cRefs = 0;
  62. m_fAttached = TRUE;
  63. m_pvDelegate = m_pfnDelegate = NULL;
  64. }
  65. //------------------------------------------------------------------------------
  66. WndBridge::~WndBridge()
  67. {
  68. AssertMsg(!m_fAttached, "WndBridge still attached at destruction!");
  69. }
  70. //------------------------------------------------------------------------------
  71. HRESULT
  72. WndBridge::Build(HWND hwnd, ATTACHWNDPROC pfnDelegate, void * pvDelegate, BOOL fAnsi)
  73. {
  74. WndBridge * pBridge = ProcessNew(WndBridge);
  75. if (pBridge == NULL) {
  76. return E_OUTOFMEMORY;
  77. } else if (pBridge->m_msgUnSubClass == 0) {
  78. return HRESULT_FROM_WIN32(GetLastError());
  79. }
  80. pBridge->m_pvDelegate = pvDelegate;
  81. pBridge->m_pfnDelegate = pfnDelegate;
  82. pBridge->m_hwnd = hwnd;
  83. pBridge->m_fAnsi = fAnsi;
  84. WNDPROC pProc = (WNDPROC)(pBridge->m_thunkUs.thunk.pThunk);
  85. WNDPROC pfnOldWndProc = NULL;
  86. if (fAnsi) {
  87. pfnOldWndProc = (WNDPROC)::SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LPARAM)pProc);
  88. } else {
  89. pfnOldWndProc = (WNDPROC)::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LPARAM)pProc);
  90. }
  91. if (pfnOldWndProc == NULL) {
  92. //
  93. // Didn't have a previous WNDPROC, so the call to SWLP failed.
  94. //
  95. ProcessDelete(WndBridge, pBridge);
  96. return E_OUTOFMEMORY;
  97. }
  98. pBridge->m_pfnOldWndProc = pfnOldWndProc;
  99. //
  100. // Once successfully created, the reference count starts at 1.
  101. //
  102. pBridge->m_cRefs = 1;
  103. return S_OK;
  104. }
  105. //------------------------------------------------------------------------------
  106. LRESULT
  107. WndBridge::RawWndProc(HWND hwndThis, UINT nMsg, WPARAM wParam, LPARAM lParam)
  108. {
  109. WndBridge * pThis = (WndBridge *) hwndThis;
  110. //
  111. // Addref the WndBridge object so that we keep it around while we are
  112. // processing this message.
  113. //
  114. pThis->AddRef();
  115. //
  116. // Cache these values because we may delete our WndBridge object during
  117. // the processing of certain messages.
  118. //
  119. HWND hwnd = pThis->m_hwnd;
  120. WNDPROC pfnOldWndProc = pThis->m_pfnOldWndProc;
  121. BOOL fAnsi = pThis->m_fAnsi;
  122. LRESULT lRet = 0;
  123. BOOL fHandled = FALSE;
  124. if (nMsg == pThis->m_msgUnSubClass) {
  125. //
  126. // We received our special message to detach. Make sure it is intended
  127. // for us (by matching proc and additional param).
  128. //
  129. if (wParam == (WPARAM)pThis->m_pfnDelegate && lParam == (LPARAM)pThis->m_pvDelegate) {
  130. lRet = (S_OK == pThis->Detach(FALSE)) ? TRUE : FALSE;
  131. fHandled = TRUE;
  132. }
  133. } else {
  134. //
  135. // Pass this message to our delegate function.
  136. //
  137. if (pThis->m_pfnDelegate != NULL) {
  138. fHandled = pThis->m_pfnDelegate(pThis->m_pvDelegate, hwnd, nMsg, wParam, lParam, &lRet);
  139. }
  140. //
  141. // Handle WM_NCDESTROY explicitly to forcibly clean up.
  142. //
  143. if (nMsg == WM_NCDESTROY) {
  144. //
  145. // The fact that we received this message means that we are still
  146. // in the call chain. This is our last chance to clean up, and
  147. // no other message should be received by this window proc again.
  148. // It is OK to force a cleanup now.
  149. //
  150. pThis->Detach(TRUE);
  151. //
  152. // Always pass the WM_NCDESTROY message down the chain!
  153. //
  154. fHandled = FALSE;
  155. }
  156. }
  157. //
  158. // If our delegate function didn't handle this message, pass it on down the chain.
  159. //
  160. if (!fHandled) {
  161. if (fAnsi) {
  162. lRet = CallWindowProcA(pfnOldWndProc, hwnd, nMsg, wParam, lParam);
  163. } else {
  164. lRet = CallWindowProcW(pfnOldWndProc, hwnd, nMsg, wParam, lParam);
  165. }
  166. }
  167. //
  168. // Release our reference. The WndBridge object may evaporate after this.
  169. //
  170. pThis->Release();
  171. return lRet;
  172. }
  173. //------------------------------------------------------------------------------
  174. // S_OK -> not attached
  175. // S_FALSE -> still attached
  176. HRESULT
  177. WndBridge::Detach(BOOL fForceCleanup)
  178. {
  179. HRESULT hr = S_FALSE;
  180. BOOL fCleanup = fForceCleanup;
  181. //
  182. // If we have already detached, return immediately.
  183. //
  184. if (!m_fAttached) {
  185. return S_OK;
  186. }
  187. //
  188. // When we detach, we simply break our connection to the delegate proc.
  189. //
  190. m_pfnDelegate = NULL;
  191. m_pvDelegate = NULL;
  192. if (!fForceCleanup) {
  193. //
  194. // Get the pointers to our thunk proc and the current window proc.
  195. //
  196. WNDPROC pfnThunk = (WNDPROC)m_thunkUs.thunk.pThunk;
  197. WNDPROC pfnWndProc = NULL;
  198. if (m_fAnsi) {
  199. pfnWndProc = (WNDPROC)::GetWindowLongPtrA(m_hwnd, GWLP_WNDPROC);
  200. } else {
  201. pfnWndProc = (WNDPROC)::GetWindowLongPtrW(m_hwnd, GWLP_WNDPROC);
  202. }
  203. AssertMsg(pfnWndProc != NULL, "Must always have a window proc!");
  204. //
  205. // If the current window proc is our own thunk proc, then we can
  206. // clean up more completely.
  207. //
  208. fCleanup = (pfnWndProc == pfnThunk);
  209. }
  210. if (fCleanup) {
  211. if (m_fAnsi) {
  212. ::SetWindowLongPtrA(m_hwnd, GWLP_WNDPROC, (LPARAM)m_pfnOldWndProc);
  213. } else {
  214. ::SetWindowLongPtrW(m_hwnd, GWLP_WNDPROC, (LPARAM)m_pfnOldWndProc);
  215. }
  216. m_fAttached = FALSE;
  217. Release();
  218. hr = S_OK;
  219. }
  220. return hr;
  221. }
  222. //------------------------------------------------------------------------------
  223. ULONG WndBridge::AddRef()
  224. {
  225. return InterlockedIncrement(&m_cRefs);
  226. }
  227. //------------------------------------------------------------------------------
  228. ULONG WndBridge::Release()
  229. {
  230. ULONG cRefs = InterlockedDecrement(&m_cRefs);
  231. if (cRefs == 0) {
  232. ProcessDelete(WndBridge, this);
  233. }
  234. return cRefs;
  235. }
  236. //------------------------------------------------------------------------------
  237. HRESULT
  238. GdAttachWndProc(HWND hwnd, ATTACHWNDPROC pfnDelegate, void * pvDelegate, BOOL fAnsi)
  239. {
  240. return WndBridge::Build(hwnd, pfnDelegate, pvDelegate, fAnsi);
  241. }
  242. //------------------------------------------------------------------------------
  243. HRESULT
  244. GdDetachWndProc(HWND hwnd, ATTACHWNDPROC pfnDelegate, void * pvDelegate)
  245. {
  246. UINT msgUnSubClass = RegisterWindowMessage(DUSERUNSUBCLASSMESSAGE);
  247. if (msgUnSubClass == 0) {
  248. return HRESULT_FROM_WIN32(GetLastError());
  249. }
  250. if (SendMessage(hwnd, msgUnSubClass, (WPARAM) pfnDelegate, (LPARAM) pvDelegate)) {
  251. return S_OK;
  252. } else {
  253. PromptInvalid("Unable to find subclass.");
  254. return E_FAIL;
  255. }
  256. }