home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / winhand.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  7KB  |  273 lines

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