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 >
Wrap
C/C++ Source or Header
|
1998-06-16
|
7KB
|
273 lines
// 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();
}