winhand.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_CORE1_SEG
  12. #pragma code_seg(AFX_CORE1_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // Support for freeing the temp maps
  21. void AFXAPI AfxLockTempMaps()
  22. {
  23. AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  24. ++pState->m_nTempMapLock;
  25. }
  26. BOOL AFXAPI AfxUnlockTempMaps(BOOL bDeleteTemps)
  27. {
  28. AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  29. if (pState->m_nTempMapLock != 0 && --pState->m_nTempMapLock == 0)
  30. {
  31. if (bDeleteTemps)
  32. {
  33. if (bDeleteTemps != -1)
  34. {
  35. // allow COM libraries to be freed
  36. CWinThread* pThread = AfxGetThread();
  37. if (pThread != NULL && pThread->m_lpfnOleTermOrFreeLib != NULL)
  38. (*pThread->m_lpfnOleTermOrFreeLib)(FALSE, FALSE);
  39. }
  40. // clean up temp objects
  41. pState->m_pmapHGDIOBJ->DeleteTemp();
  42. pState->m_pmapHDC->DeleteTemp();
  43. pState->m_pmapHMENU->DeleteTemp();
  44. pState->m_pmapHWND->DeleteTemp();
  45. pState->m_pmapHIMAGELIST->DeleteTemp();
  46. }
  47. #ifndef _AFX_PORTABLE
  48. CWinApp* pApp = AfxGetApp();
  49. _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  50. // restore safety pool after temp objects destroyed
  51. if (pApp != NULL &&
  52. (pThreadState->m_pSafetyPoolBuffer == NULL ||
  53. _msize(pThreadState->m_pSafetyPoolBuffer) < pApp->m_nSafetyPoolSize) &&
  54. pApp->m_nSafetyPoolSize != 0)
  55. {
  56. // attempt to restore the safety pool to its max size
  57. size_t nOldSize = 0;
  58. if (pThreadState->m_pSafetyPoolBuffer != NULL)
  59. {
  60. nOldSize = _msize(pThreadState->m_pSafetyPoolBuffer);
  61. free(pThreadState->m_pSafetyPoolBuffer);
  62. }
  63. // undo handler trap for the following allocation
  64. BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  65. pThreadState->m_pSafetyPoolBuffer = malloc(pApp->m_nSafetyPoolSize);
  66. if (pThreadState->m_pSafetyPoolBuffer == NULL)
  67. {
  68. TRACE1("Warning: failed to reclaim %d bytes for memory safety pool.\n",
  69. pApp->m_nSafetyPoolSize);
  70. // at least get the old buffer back
  71. if (nOldSize != 0)
  72. {
  73. //get it back
  74. pThreadState->m_pSafetyPoolBuffer = malloc(nOldSize);
  75. ASSERT(pThreadState->m_pSafetyPoolBuffer != NULL);
  76. }
  77. }
  78. AfxEnableMemoryTracking(bEnable);
  79. }
  80. #endif // !_AFX_PORTABLE
  81. }
  82. // return TRUE if temp maps still locked
  83. return pState->m_nTempMapLock != 0;
  84. }
  85. /////////////////////////////////////////////////////////////////////////////
  86. // CHandleMap implementation
  87. CHandleMap::CHandleMap(CRuntimeClass* pClass, size_t nOffset, int nHandles)
  88. : m_permanentMap(10), m_temporaryMap(4)
  89. // small block size for temporary map
  90. {
  91. ASSERT(pClass != NULL);
  92. ASSERT(nHandles == 1 || nHandles == 2);
  93. m_temporaryMap.InitHashTable(7, FALSE); // small table for temporary map
  94. m_pClass = pClass;
  95. m_nOffset = nOffset;
  96. m_nHandles = nHandles;
  97. }
  98. CObject* CHandleMap::FromHandle(HANDLE h)
  99. {
  100. ASSERT(m_pClass != NULL);
  101. ASSERT(m_nHandles == 1 || m_nHandles == 2);
  102. if (h == NULL)
  103. return NULL;
  104. CObject* pObject = LookupPermanent(h);
  105. if (pObject != NULL)
  106. return pObject; // return permanent one
  107. else if ((pObject = LookupTemporary(h)) != NULL)
  108. {
  109. HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset);
  110. ASSERT(ph[0] == h || ph[0] == NULL);
  111. ph[0] = h;
  112. if (m_nHandles == 2)
  113. {
  114. ASSERT(ph[1] == h || ph[1] == NULL);
  115. ph[1] = h;
  116. }
  117. return pObject; // return current temporary one
  118. }
  119. // This handle wasn't created by us, so we must create a temporary
  120. // C++ object to wrap it. We don't want the user to see this memory
  121. // allocation, so we turn tracing off.
  122. BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  123. #ifndef _AFX_PORTABLE
  124. _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
  125. #endif
  126. CObject* pTemp = NULL;
  127. TRY
  128. {
  129. pTemp = m_pClass->CreateObject();
  130. if (pTemp == NULL)
  131. AfxThrowMemoryException();
  132. m_temporaryMap.SetAt((LPVOID)h, pTemp);
  133. }
  134. CATCH_ALL(e)
  135. {
  136. #ifndef _AFX_PORTABLE
  137. AfxSetNewHandler(pnhOldHandler);
  138. #endif
  139. AfxEnableMemoryTracking(bEnable);
  140. THROW_LAST();
  141. }
  142. END_CATCH_ALL
  143. #ifndef _AFX_PORTABLE
  144. AfxSetNewHandler(pnhOldHandler);
  145. #endif
  146. AfxEnableMemoryTracking(bEnable);
  147. // now set the handle in the object
  148. HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
  149. ph[0] = h;
  150. if (m_nHandles == 2)
  151. ph[1] = h;
  152. return pTemp;
  153. }
  154. #ifdef _DEBUG // out-of-line version for memory tracking
  155. void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)
  156. {
  157. BOOL bEnable = AfxEnableMemoryTracking(FALSE);
  158. m_permanentMap[(LPVOID)h] = permOb;
  159. AfxEnableMemoryTracking(bEnable);
  160. }
  161. #endif //_DEBUG
  162. #ifdef _DEBUG
  163. void CHandleMap::RemoveHandle(HANDLE h)
  164. {
  165. // make sure the handle entry is consistent before deleting
  166. CObject* pTemp = LookupTemporary(h);
  167. if (pTemp != NULL)
  168. {
  169. // temporary objects must have correct handle values
  170. HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
  171. ASSERT(ph[0] == h || ph[0] == NULL);
  172. if (m_nHandles == 2)
  173. ASSERT(ph[1] == h);
  174. }
  175. pTemp = LookupPermanent(h);
  176. if (pTemp != NULL)
  177. {
  178. HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
  179. ASSERT(ph[0] == h);
  180. // permanent object may have secondary handles that are different
  181. }
  182. // remove only from permanent map -- temporary objects are removed
  183. // at idle in CHandleMap::DeleteTemp, always!
  184. m_permanentMap.RemoveKey((LPVOID)h);
  185. }
  186. #endif
  187. void CHandleMap::DeleteTemp()
  188. {
  189. if (this == NULL)
  190. return;
  191. POSITION pos = m_temporaryMap.GetStartPosition();
  192. while (pos != NULL)
  193. {
  194. HANDLE h; // just used for asserts
  195. CObject* pTemp;
  196. m_temporaryMap.GetNextAssoc(pos, (LPVOID&)h, (void*&)pTemp);
  197. // zero out the handles
  198. ASSERT(m_nHandles == 1 || m_nHandles == 2);
  199. HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
  200. ASSERT(ph[0] == h || ph[0] == NULL);
  201. ph[0] = NULL;
  202. if (m_nHandles == 2)
  203. {
  204. ASSERT(ph[1] == h || ph[1] == NULL);
  205. ph[1] = NULL;
  206. }
  207. delete pTemp; // virtual destructor does the right thing
  208. }
  209. m_temporaryMap.RemoveAll(); // free up dictionary links etc
  210. }
  211. /////////////////////////////////////////////////////////////////////////////
  212. void PASCAL CWnd::DeleteTempMap()
  213. {
  214. CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHWND;
  215. pMap->DeleteTemp();
  216. }
  217. void PASCAL CImageList::DeleteTempMap()
  218. {
  219. CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHIMAGELIST;
  220. pMap->DeleteTemp();
  221. }
  222. void PASCAL CDC::DeleteTempMap()
  223. {
  224. CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHDC;
  225. pMap->DeleteTemp();
  226. }
  227. void PASCAL CGdiObject::DeleteTempMap()
  228. {
  229. CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHGDIOBJ;
  230. pMap->DeleteTemp();
  231. }
  232. void PASCAL CMenu::DeleteTempMap()
  233. {
  234. CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHMENU;
  235. pMap->DeleteTemp();
  236. }