home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
-
- #ifdef AFX_CORE1_SEG
- #pragma code_seg(AFX_CORE1_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- #define new DEBUG_NEW
-
- /////////////////////////////////////////////////////////////////////////////
- // Support for freeing the temp maps
-
- void AFXAPI AfxLockTempMaps()
- {
- AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
- ++pState->m_nTempMapLock;
- }
-
- BOOL AFXAPI AfxUnlockTempMaps(BOOL bDeleteTemps)
- {
- AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
- if (pState->m_nTempMapLock != 0 && --pState->m_nTempMapLock == 0)
- {
- if (bDeleteTemps)
- {
- if (bDeleteTemps != -1)
- {
- // allow COM libraries to be freed
- CWinThread* pThread = AfxGetThread();
- if (pThread != NULL && pThread->m_lpfnOleTermOrFreeLib != NULL)
- (*pThread->m_lpfnOleTermOrFreeLib)(FALSE, FALSE);
- }
-
- // clean up temp objects
- pState->m_pmapHGDIOBJ->DeleteTemp();
- pState->m_pmapHDC->DeleteTemp();
- pState->m_pmapHMENU->DeleteTemp();
- pState->m_pmapHWND->DeleteTemp();
- pState->m_pmapHIMAGELIST->DeleteTemp();
- }
-
- #ifndef _AFX_PORTABLE
- CWinApp* pApp = AfxGetApp();
- _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
- // restore safety pool after temp objects destroyed
- if (pApp != NULL &&
- (pThreadState->m_pSafetyPoolBuffer == NULL ||
- _msize(pThreadState->m_pSafetyPoolBuffer) < pApp->m_nSafetyPoolSize) &&
- pApp->m_nSafetyPoolSize != 0)
- {
- // attempt to restore the safety pool to its max size
- size_t nOldSize = 0;
- if (pThreadState->m_pSafetyPoolBuffer != NULL)
- {
- nOldSize = _msize(pThreadState->m_pSafetyPoolBuffer);
- free(pThreadState->m_pSafetyPoolBuffer);
- }
-
- // undo handler trap for the following allocation
- BOOL bEnable = AfxEnableMemoryTracking(FALSE);
- pThreadState->m_pSafetyPoolBuffer = malloc(pApp->m_nSafetyPoolSize);
- if (pThreadState->m_pSafetyPoolBuffer == NULL)
- {
- TRACE1("Warning: failed to reclaim %d bytes for memory safety pool.\n",
- pApp->m_nSafetyPoolSize);
- // at least get the old buffer back
- if (nOldSize != 0)
- {
- //get it back
- pThreadState->m_pSafetyPoolBuffer = malloc(nOldSize);
- ASSERT(pThreadState->m_pSafetyPoolBuffer != NULL);
- }
- }
- AfxEnableMemoryTracking(bEnable);
- }
- #endif // !_AFX_PORTABLE
- }
-
- // return TRUE if temp maps still locked
- return pState->m_nTempMapLock != 0;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CHandleMap implementation
-
- CHandleMap::CHandleMap(CRuntimeClass* pClass, size_t nOffset, int nHandles)
- : m_permanentMap(10), m_temporaryMap(4)
- // small block size for temporary map
- {
- ASSERT(pClass != NULL);
- ASSERT(nHandles == 1 || nHandles == 2);
-
- m_temporaryMap.InitHashTable(7, FALSE); // small table for temporary map
- m_pClass = pClass;
- m_nOffset = nOffset;
- m_nHandles = nHandles;
- }
-
- CObject* CHandleMap::FromHandle(HANDLE h)
- {
- ASSERT(m_pClass != NULL);
- ASSERT(m_nHandles == 1 || m_nHandles == 2);
-
- if (h == NULL)
- return NULL;
-
- CObject* pObject = LookupPermanent(h);
- if (pObject != NULL)
- return pObject; // return permanent one
- else if ((pObject = LookupTemporary(h)) != NULL)
- {
- HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset);
- ASSERT(ph[0] == h || ph[0] == NULL);
- ph[0] = h;
- if (m_nHandles == 2)
- {
- ASSERT(ph[1] == h || ph[1] == NULL);
- ph[1] = h;
- }
- return pObject; // return current temporary one
- }
-
- // This handle wasn't created by us, so we must create a temporary
- // C++ object to wrap it. We don't want the user to see this memory
- // allocation, so we turn tracing off.
-
- BOOL bEnable = AfxEnableMemoryTracking(FALSE);
- #ifndef _AFX_PORTABLE
- _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
- #endif
-
- CObject* pTemp = NULL;
- TRY
- {
- pTemp = m_pClass->CreateObject();
- if (pTemp == NULL)
- AfxThrowMemoryException();
-
- m_temporaryMap.SetAt((LPVOID)h, pTemp);
- }
- CATCH_ALL(e)
- {
- #ifndef _AFX_PORTABLE
- AfxSetNewHandler(pnhOldHandler);
- #endif
- AfxEnableMemoryTracking(bEnable);
- THROW_LAST();
- }
- END_CATCH_ALL
-
- #ifndef _AFX_PORTABLE
- AfxSetNewHandler(pnhOldHandler);
- #endif
- AfxEnableMemoryTracking(bEnable);
-
- // now set the handle in the object
- HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
- ph[0] = h;
- if (m_nHandles == 2)
- ph[1] = h;
-
- return pTemp;
- }
-
- #ifdef _DEBUG // out-of-line version for memory tracking
- void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)
- {
- BOOL bEnable = AfxEnableMemoryTracking(FALSE);
- m_permanentMap[(LPVOID)h] = permOb;
- AfxEnableMemoryTracking(bEnable);
- }
- #endif //_DEBUG
-
- #ifdef _DEBUG
- void CHandleMap::RemoveHandle(HANDLE h)
- {
- // make sure the handle entry is consistent before deleting
- CObject* pTemp = LookupTemporary(h);
- if (pTemp != NULL)
- {
- // temporary objects must have correct handle values
- HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
- ASSERT(ph[0] == h || ph[0] == NULL);
- if (m_nHandles == 2)
- ASSERT(ph[1] == h);
- }
- pTemp = LookupPermanent(h);
- if (pTemp != NULL)
- {
- HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
- ASSERT(ph[0] == h);
- // permanent object may have secondary handles that are different
- }
- // remove only from permanent map -- temporary objects are removed
- // at idle in CHandleMap::DeleteTemp, always!
- m_permanentMap.RemoveKey((LPVOID)h);
- }
- #endif
-
- void CHandleMap::DeleteTemp()
- {
- if (this == NULL)
- return;
-
- POSITION pos = m_temporaryMap.GetStartPosition();
- while (pos != NULL)
- {
- HANDLE h; // just used for asserts
- CObject* pTemp;
- m_temporaryMap.GetNextAssoc(pos, (LPVOID&)h, (void*&)pTemp);
-
- // zero out the handles
- ASSERT(m_nHandles == 1 || m_nHandles == 2);
- HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
- ASSERT(ph[0] == h || ph[0] == NULL);
- ph[0] = NULL;
- if (m_nHandles == 2)
- {
- ASSERT(ph[1] == h || ph[1] == NULL);
- ph[1] = NULL;
- }
- delete pTemp; // virtual destructor does the right thing
- }
-
- m_temporaryMap.RemoveAll(); // free up dictionary links etc
- }
-
- /////////////////////////////////////////////////////////////////////////////
-
- void PASCAL CWnd::DeleteTempMap()
- {
- CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHWND;
- pMap->DeleteTemp();
- }
-
- void PASCAL CImageList::DeleteTempMap()
- {
- CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHIMAGELIST;
- pMap->DeleteTemp();
- }
-
- void PASCAL CDC::DeleteTempMap()
- {
- CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHDC;
- pMap->DeleteTemp();
- }
-
- void PASCAL CGdiObject::DeleteTempMap()
- {
- CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHGDIOBJ;
- pMap->DeleteTemp();
- }
-
- void PASCAL CMenu::DeleteTempMap()
- {
- CHandleMap* pMap = AfxGetModuleThreadState()->m_pmapHMENU;
- pMap->DeleteTemp();
- }
-