822 lines
21 KiB
C++
822 lines
21 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// File:
|
||
|
// global.cpp
|
||
|
//
|
||
|
// Contents:
|
||
|
// Ut functions that deal with HGlobals for debugging;
|
||
|
// see le2int.h
|
||
|
//
|
||
|
// Classes:
|
||
|
//
|
||
|
// Functions:
|
||
|
// UtGlobalAlloc
|
||
|
// UtGlobalReAlloc
|
||
|
// UtGlobalLock
|
||
|
// UtGlobalUnlock
|
||
|
// UtGlobalFree
|
||
|
// UtGlobalFlush
|
||
|
// UtSetClipboardData
|
||
|
//
|
||
|
// History:
|
||
|
// 12/20/93 - ChrisWe - created
|
||
|
// 01/11/94 - alexgo - added VDATEHEAP macros to every function
|
||
|
// 02/25/94 AlexT Add some generic integrity checking
|
||
|
// 03/30/94 AlexT Add UtSetClipboardData
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// These routines are designed to catch bugs that corrupt GlobalAlloc memory.
|
||
|
// We cannot guarantee that all global memory will be manipulated with these
|
||
|
// routines (e.g. OLE might allocate a handle and the client application
|
||
|
// might free it), so we can't require that these routines be used in pairs.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include <le2int.h>
|
||
|
|
||
|
#if DBG==1 && defined(WIN32)
|
||
|
#include <olesem.hxx>
|
||
|
|
||
|
ASSERTDATA
|
||
|
|
||
|
// undefine these, so we don't call ourselves recursively
|
||
|
// if this module is used, these are defined in le2int.h to replace
|
||
|
// the existing allocator with the functions here
|
||
|
#undef GlobalAlloc
|
||
|
#undef GlobalReAlloc
|
||
|
#undef GlobalLock
|
||
|
#undef GlobalUnlock
|
||
|
#undef GlobalFree
|
||
|
#undef SetClipboardData
|
||
|
|
||
|
// Same ones as in memapi.cxx
|
||
|
#define OLEMEM_ALLOCBYTE 0xde
|
||
|
#define OLEMEM_FREEBYTE 0xed
|
||
|
|
||
|
typedef struct s_GlobalAllocInfo
|
||
|
{
|
||
|
HGLOBAL hGlobal; // A GlobalAlloc'd HGLOBAL
|
||
|
ULONG cbGlobalSize; // GlobalSize(hGlobal)
|
||
|
ULONG cbUser; // size requested by caller
|
||
|
ULONG ulIndex; // allocation index (1st, 2nd...)
|
||
|
struct s_GlobalAllocInfo *pNext;
|
||
|
} SGLOBALALLOCINFO, *PSGLOBALALLOCINFO;
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CGlobalTrack
|
||
|
//
|
||
|
// Purpose: GlobalAlloc memory tracking
|
||
|
//
|
||
|
// History: 25-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
class CGlobalTrack
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
//
|
||
|
// We only have a constructor for debug builds, to ensure this object
|
||
|
// is statically allocated. Statically allocated objects are initialized
|
||
|
// to all zeroes, which is what we need.
|
||
|
//
|
||
|
|
||
|
CGlobalTrack();
|
||
|
|
||
|
HGLOBAL cgtGlobalAlloc(UINT uiFlag, DWORD cbUser);
|
||
|
HGLOBAL cgtGlobalReAlloc(HGLOBAL hGlobal, DWORD cbUser, UINT uiFlag);
|
||
|
HGLOBAL cgtGlobalFree(HGLOBAL hGlobal);
|
||
|
LPVOID cgtGlobalLock(HGLOBAL hGlobal);
|
||
|
BOOL cgtGlobalUnlock(HGLOBAL hGlobal);
|
||
|
|
||
|
void cgtVerifyAll(void);
|
||
|
void cgtFlushTracking(void);
|
||
|
BOOL cgtStopTracking(HGLOBAL hGlobal);
|
||
|
|
||
|
private:
|
||
|
ULONG CalculateAllocSize(ULONG cbUser);
|
||
|
void InitializeRegion(HGLOBAL hGlobal, ULONG cbStart, ULONG cbEnd);
|
||
|
void Track(HGLOBAL hGlobal, ULONG cbUser);
|
||
|
void Retrack(HGLOBAL hOld, HGLOBAL hNew);
|
||
|
void VerifyHandle(HGLOBAL hGlobal);
|
||
|
|
||
|
ULONG _ulIndex;
|
||
|
PSGLOBALALLOCINFO _pRoot;
|
||
|
static COleStaticMutexSem _mxsGlobalMemory;
|
||
|
};
|
||
|
|
||
|
COleStaticMutexSem CGlobalTrack::_mxsGlobalMemory;
|
||
|
|
||
|
CGlobalTrack gGlobalTrack;
|
||
|
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::CGlobalTrack, public
|
||
|
//
|
||
|
// Synopsis: constructor
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CGlobalTrack::CGlobalTrack()
|
||
|
{
|
||
|
Win4Assert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
|
||
|
Win4Assert (_pRoot == NULL && _ulIndex == 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtGlobalAlloc, public
|
||
|
//
|
||
|
// Synopsis: Debugging version of GlobalAlloc
|
||
|
//
|
||
|
// Arguments: [uiFlag] -- allocation flags
|
||
|
// [cbUser] -- requested allocation size
|
||
|
//
|
||
|
// Requires: We must return a "real" GlobalAlloc'd pointer, because
|
||
|
// we may not necessarily be the ones to free it.
|
||
|
//
|
||
|
// Returns: HGLOBAL
|
||
|
//
|
||
|
// Algorithm: We allocate an extra amount to form a tail and initialize it
|
||
|
// to a known value.
|
||
|
//
|
||
|
// History: 25-Feb-94 AlexT Added this prologue
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HGLOBAL CGlobalTrack::cgtGlobalAlloc(UINT uiFlag, DWORD cbUser)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
ULONG cbAlloc;
|
||
|
HGLOBAL hGlobal;
|
||
|
|
||
|
cbAlloc = CalculateAllocSize(cbUser);
|
||
|
hGlobal = GlobalAlloc(uiFlag, cbAlloc);
|
||
|
if (NULL == hGlobal)
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "GlobalAlloc(%ld) failed - %lx\n", cbAlloc,
|
||
|
GetLastError()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (uiFlag & GMEM_ZEROINIT)
|
||
|
{
|
||
|
// Caller asked for zeroinit, so we only initialize the tail
|
||
|
InitializeRegion(hGlobal, cbUser, cbAlloc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Caller did not ask for zeroinit, so we initialize the whole
|
||
|
// region
|
||
|
InitializeRegion(hGlobal, 0, cbAlloc);
|
||
|
}
|
||
|
|
||
|
Track(hGlobal, cbUser);
|
||
|
}
|
||
|
|
||
|
return(hGlobal);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtGlobalReAlloc, public
|
||
|
//
|
||
|
// Synopsis: Debugging version of GlobalReAlloc
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- handle to reallocate
|
||
|
// [cbUser] -- requested allocation size
|
||
|
// [uiFlag] -- allocation flags
|
||
|
//
|
||
|
// Returns: reallocated handle
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// if (modify only)
|
||
|
// reallocate
|
||
|
// else
|
||
|
// reallocate with tail
|
||
|
// initialize tail
|
||
|
//
|
||
|
// update tracking information
|
||
|
//
|
||
|
// History: 25-Feb-94 AlexT Added this prologue
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HGLOBAL CGlobalTrack::cgtGlobalReAlloc(HGLOBAL hGlobal, DWORD cbUser, UINT uiFlag)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
HGLOBAL hNew;
|
||
|
ULONG cbAlloc;
|
||
|
|
||
|
VerifyHandle(hGlobal);
|
||
|
|
||
|
if (uiFlag & GMEM_MODIFY)
|
||
|
{
|
||
|
// We're not changing sizes, so there's no work for us to do
|
||
|
|
||
|
LEDebugOut((DEB_WARN, "UtGlobalReAlloc modifying global handle\n"));
|
||
|
hNew = GlobalReAlloc(hGlobal, cbUser, uiFlag);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cbAlloc = CalculateAllocSize(cbUser);
|
||
|
hNew = GlobalReAlloc(hGlobal, cbAlloc, uiFlag);
|
||
|
if (NULL == hNew)
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "GlobalReAlloc failed - %lx\n",
|
||
|
GetLastError()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
InitializeRegion(hNew, cbUser, cbAlloc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != hNew)
|
||
|
{
|
||
|
if (uiFlag & GMEM_MODIFY)
|
||
|
{
|
||
|
// Retrack will only track hNew if we were tracking hGlobal
|
||
|
Retrack(hGlobal, hNew);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We've allocated a new block, so we always want to track the
|
||
|
// new one
|
||
|
cgtStopTracking(hGlobal);
|
||
|
Track(hNew, cbUser);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(hNew);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtGlobalFree, public
|
||
|
//
|
||
|
// Synopsis: Debugging version of GlobalReAlloc
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global handle to free
|
||
|
//
|
||
|
// Returns: Same as GlobalFree
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 25-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HGLOBAL CGlobalTrack::cgtGlobalFree(HGLOBAL hGlobal)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
HGLOBAL hReturn;
|
||
|
|
||
|
VerifyHandle(hGlobal);
|
||
|
|
||
|
hReturn = GlobalFree(hGlobal);
|
||
|
|
||
|
if (NULL == hReturn)
|
||
|
{
|
||
|
cgtStopTracking(hGlobal);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "GlobalFree did not free %lx\n", hGlobal));
|
||
|
}
|
||
|
|
||
|
return(hReturn);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtGlobalLock, public
|
||
|
//
|
||
|
// Synopsis: Debugging version of GlobalLock
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global memory handle
|
||
|
//
|
||
|
// Returns: Same as GlobalLock
|
||
|
//
|
||
|
// History: 25-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
LPVOID CGlobalTrack::cgtGlobalLock(HGLOBAL hGlobal)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
VerifyHandle(hGlobal);
|
||
|
return(GlobalLock(hGlobal));
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtGlobalUnlock, public
|
||
|
//
|
||
|
// Synopsis: Debugging version of GlobalUnlock
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global memory handle
|
||
|
//
|
||
|
// Returns: Same as GlobalUnlock
|
||
|
//
|
||
|
// History: 25-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CGlobalTrack::cgtGlobalUnlock(HGLOBAL hGlobal)
|
||
|
{
|
||
|
VDATEHEAP();
|
||
|
|
||
|
VerifyHandle(hGlobal);
|
||
|
return(GlobalUnlock(hGlobal));
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtVerifyAll, public
|
||
|
//
|
||
|
// Synopsis: Verify all tracked handles
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CGlobalTrack::cgtVerifyAll(void)
|
||
|
{
|
||
|
VerifyHandle(NULL);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtFlushTracking
|
||
|
//
|
||
|
// Synopsis: Stops all tracking
|
||
|
//
|
||
|
// Effects: Frees all internal memory
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CGlobalTrack::cgtFlushTracking(void)
|
||
|
{
|
||
|
COleStaticLock lck(_mxsGlobalMemory);
|
||
|
BOOL bResult;
|
||
|
|
||
|
while (NULL != _pRoot)
|
||
|
{
|
||
|
bResult = cgtStopTracking(_pRoot->hGlobal);
|
||
|
Assert(bResult && "CGT::cgtFlushTracking problem");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::CalculateAllocSize, private
|
||
|
//
|
||
|
// Synopsis: calculate total allocation size (inluding tail)
|
||
|
//
|
||
|
// Arguments: [cbUser] -- requested size
|
||
|
//
|
||
|
// Returns: total count of bytes to allocate
|
||
|
//
|
||
|
// Algorithm: calculate bytes needed to have at least one guard page at the
|
||
|
// end
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes: By keeping this calculation in one location we make it
|
||
|
// easier to maintain.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CGlobalTrack::CalculateAllocSize(ULONG cbUser)
|
||
|
{
|
||
|
SYSTEM_INFO si;
|
||
|
ULONG cbAlloc;
|
||
|
|
||
|
#ifdef _CHICAGO_
|
||
|
// BUGBUG Chicago: GetSystemInfo not yet implemented
|
||
|
si.dwPageSize = 0x1000;
|
||
|
#else
|
||
|
GetSystemInfo(&si);
|
||
|
#endif
|
||
|
|
||
|
// Calculate how many pages are need to cover cbUser
|
||
|
cbAlloc = ((cbUser + si.dwPageSize - 1) / si.dwPageSize) * si.dwPageSize;
|
||
|
|
||
|
// Add an extra page so that the tail is at least one page long
|
||
|
cbAlloc += si.dwPageSize;
|
||
|
|
||
|
return(cbAlloc);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::InitializeRegion, private
|
||
|
//
|
||
|
// Synopsis: initialize region to bad value
|
||
|
//
|
||
|
// Effects: fills in memory region
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global memory handle
|
||
|
// [cbStart] -- count of bytes to skip
|
||
|
// [cbEnd] -- end offset (exclusive)
|
||
|
//
|
||
|
// Requires: cbEnd > cbStart
|
||
|
//
|
||
|
// Algorithm: fill in hGlobal from cbStart (inclusive) to cbEnd (exclusive)
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CGlobalTrack::InitializeRegion(HGLOBAL hGlobal, ULONG cbStart, ULONG cbEnd)
|
||
|
{
|
||
|
BYTE *pbStart;
|
||
|
BYTE *pb;
|
||
|
|
||
|
Assert(cbStart < cbEnd && "illogical parameters");
|
||
|
Assert(cbEnd <= GlobalSize(hGlobal) && "global memory too small");
|
||
|
|
||
|
// GlobalLock on GMEM_FIXED memory is a nop, so this is a safe call
|
||
|
pbStart = (BYTE *) GlobalLock(hGlobal);
|
||
|
|
||
|
if (NULL == pbStart)
|
||
|
{
|
||
|
// Shouldn't have failed - (we allocated > 0 bytes)
|
||
|
|
||
|
LEDebugOut((DEB_WARN, "GlobalLock failed - %lx\n", GetLastError()));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Initialize the tail portion of the memory
|
||
|
for (pb = pbStart + cbStart; pb < pbStart + cbEnd; pb++)
|
||
|
{
|
||
|
*pb = OLEMEM_ALLOCBYTE;
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(hGlobal);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::Track, private
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global memory handle
|
||
|
// [cbUser] -- user allocation size
|
||
|
//
|
||
|
// Requires:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Signals:
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Derivation:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CGlobalTrack::Track(HGLOBAL hGlobal, ULONG cbUser)
|
||
|
{
|
||
|
COleStaticLock lck(_mxsGlobalMemory);
|
||
|
PSGLOBALALLOCINFO pgi;
|
||
|
|
||
|
if (cgtStopTracking(hGlobal))
|
||
|
{
|
||
|
// If it's already in our list, it's possible that someone else
|
||
|
// freed the HGLOBAL without telling us - remove our stale one
|
||
|
LEDebugOut((DEB_WARN, "CGT::Track - %lx was already in list!\n",
|
||
|
hGlobal));
|
||
|
}
|
||
|
|
||
|
pgi = (PSGLOBALALLOCINFO) PrivMemAlloc(sizeof(SGLOBALALLOCINFO));
|
||
|
if (NULL == pgi)
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "CGT::Insert - PrivMemAlloc failed\n"));
|
||
|
|
||
|
// Okay fine - we just won't track this one
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pgi->hGlobal = hGlobal;
|
||
|
pgi->cbGlobalSize = GlobalSize(hGlobal);
|
||
|
Assert((0 == cbUser || pgi->cbGlobalSize > 0) && "GlobalSize failed - bad handle?");
|
||
|
pgi->cbUser = cbUser;
|
||
|
pgi->ulIndex = ++_ulIndex;
|
||
|
pgi->pNext = _pRoot;
|
||
|
_pRoot = pgi;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::Retrack, private
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hOld] -- previous handle
|
||
|
// [hNew] -- new handle
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CGlobalTrack::Retrack(HGLOBAL hOld, HGLOBAL hNew)
|
||
|
{
|
||
|
COleStaticLock lck(_mxsGlobalMemory);
|
||
|
PSGLOBALALLOCINFO pgi;
|
||
|
|
||
|
if (hOld != hNew && cgtStopTracking(hNew))
|
||
|
{
|
||
|
// If hNew was already in the list, it's possible that someone else
|
||
|
// freed the HGLOBAL without telling us so we removed the stale one
|
||
|
LEDebugOut((DEB_WARN, "CGT::Retrack - %lx was already in list!\n", hNew));
|
||
|
}
|
||
|
|
||
|
for (pgi = _pRoot; NULL != pgi; pgi = pgi->pNext)
|
||
|
{
|
||
|
if (pgi->hGlobal == hOld)
|
||
|
{
|
||
|
pgi->hGlobal = hNew;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL == pgi)
|
||
|
{
|
||
|
// We didn't find hOld
|
||
|
LEDebugOut((DEB_WARN, "CGT::Retrack - hOld (%lx) not found\n", hOld));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::cgtStopTracking, public
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global handle
|
||
|
//
|
||
|
// Modifies:
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CGlobalTrack::cgtStopTracking(HGLOBAL hGlobal)
|
||
|
{
|
||
|
COleStaticLock lck(_mxsGlobalMemory);
|
||
|
PSGLOBALALLOCINFO *ppgi = &_pRoot;
|
||
|
PSGLOBALALLOCINFO pgi;
|
||
|
|
||
|
while (*ppgi != NULL && (*ppgi)->hGlobal != hGlobal)
|
||
|
{
|
||
|
ppgi = &((*ppgi)->pNext);
|
||
|
}
|
||
|
|
||
|
if (NULL == *ppgi)
|
||
|
{
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
pgi = *ppgi;
|
||
|
Assert(pgi->hGlobal == hGlobal && "CGT::cgtStopTracking search problem");
|
||
|
|
||
|
*ppgi = pgi->pNext;
|
||
|
|
||
|
PrivMemFree(pgi);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CGlobalTrack::VerifyHandle, private
|
||
|
//
|
||
|
// Synopsis: Verify global handle
|
||
|
//
|
||
|
// Arguments: [hGlobal] -- global memory handle
|
||
|
//
|
||
|
// Signals: Asserts if bad
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
// 22-Jun-94 AlexT Allow for handle to have been freed and
|
||
|
// reallocated under us
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CGlobalTrack::VerifyHandle(HGLOBAL hGlobal)
|
||
|
{
|
||
|
COleStaticLock lck(_mxsGlobalMemory);
|
||
|
PSGLOBALALLOCINFO pgi, pgiNext;
|
||
|
ULONG cbAlloc;
|
||
|
BYTE *pbStart;
|
||
|
BYTE *pb;
|
||
|
|
||
|
// Note that we use a while loop (recording pgiNext up front) instead
|
||
|
// of a for loop because pgi will get removed from the list if we call
|
||
|
// cgtStopTracking on it
|
||
|
|
||
|
pgi = _pRoot;
|
||
|
while (NULL != pgi)
|
||
|
{
|
||
|
pgiNext = pgi->pNext;
|
||
|
|
||
|
if (NULL == hGlobal || pgi->hGlobal == hGlobal)
|
||
|
{
|
||
|
if (pgi->cbGlobalSize != GlobalSize(pgi->hGlobal))
|
||
|
{
|
||
|
// pgi->hGlobal's size has changed since we started tracking
|
||
|
// it; it must have been freed or reallocated by someone
|
||
|
// else. Stop tracking it.
|
||
|
|
||
|
// This call will remove pgi from the list (so we NULL it to
|
||
|
// make sure we don't try reusing it)!
|
||
|
|
||
|
cgtStopTracking(pgi->hGlobal);
|
||
|
pgi = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cbAlloc = CalculateAllocSize(pgi->cbUser);
|
||
|
|
||
|
pbStart = (BYTE *) GlobalLock(pgi->hGlobal);
|
||
|
|
||
|
// it is legitimate to have a zero length (NULL memory) handle
|
||
|
if (NULL == pbStart)
|
||
|
{
|
||
|
LEDebugOut((DEB_WARN, "GlobalLock failed - %lx\n",
|
||
|
GetLastError()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (pb = pbStart + pgi->cbUser;
|
||
|
pb < pbStart + cbAlloc;
|
||
|
pb++)
|
||
|
{
|
||
|
if (*pb != OLEMEM_ALLOCBYTE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pb < pbStart + cbAlloc)
|
||
|
{
|
||
|
// In general an application may have freed and reallocated
|
||
|
// any HGLOBAL, so we can only warn about corruption.
|
||
|
|
||
|
LEDebugOut((DEB_WARN, "HGLOBAL #%ld may be corrupt\n",
|
||
|
pgi->ulIndex));
|
||
|
#ifdef GLOBALDBG
|
||
|
// If GLOBALDBG is true, then all allocations should be
|
||
|
// coming through these routines. In this case we assert
|
||
|
// if we've found corruption.
|
||
|
Assert(0 && "CGlobalTrack::VerifyHandle - HGLOBAL corrupt");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(pgi->hGlobal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pgi = pgiNext;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtGlobalAlloc, ReAlloc, Free, Lock, Unlock
|
||
|
//
|
||
|
// Synopsis: Debug versions of Global memory routines
|
||
|
//
|
||
|
// Arguments: Same as Windows APIs
|
||
|
//
|
||
|
// History: 28-Feb-94 AlexT Created
|
||
|
//
|
||
|
// Notes: These entry points just call the worker routines
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" HGLOBAL WINAPI UtGlobalAlloc(UINT uiFlag, DWORD cbUser)
|
||
|
{
|
||
|
return gGlobalTrack.cgtGlobalAlloc(uiFlag, cbUser);
|
||
|
}
|
||
|
|
||
|
extern "C" HGLOBAL WINAPI UtGlobalReAlloc(HGLOBAL hGlobal, DWORD cbUser, UINT uiFlag)
|
||
|
{
|
||
|
return gGlobalTrack.cgtGlobalReAlloc(hGlobal, cbUser, uiFlag);
|
||
|
}
|
||
|
|
||
|
extern "C" LPVOID WINAPI UtGlobalLock(HGLOBAL hGlobal)
|
||
|
{
|
||
|
return gGlobalTrack.cgtGlobalLock(hGlobal);
|
||
|
}
|
||
|
|
||
|
extern "C" BOOL WINAPI UtGlobalUnlock(HGLOBAL hGlobal)
|
||
|
{
|
||
|
return gGlobalTrack.cgtGlobalUnlock(hGlobal);
|
||
|
}
|
||
|
|
||
|
extern "C" HGLOBAL WINAPI UtGlobalFree(HGLOBAL hGlobal)
|
||
|
{
|
||
|
return gGlobalTrack.cgtGlobalFree(hGlobal);
|
||
|
}
|
||
|
|
||
|
extern "C" void UtGlobalFlushTracking(void)
|
||
|
{
|
||
|
gGlobalTrack.cgtFlushTracking();
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UtSetClipboardData
|
||
|
//
|
||
|
// Synopsis: Calls Windows SetClipboardData and stops tracking the handle
|
||
|
//
|
||
|
// Arguments: [uFormat] -- clipboard format
|
||
|
// [hMem] -- data handle
|
||
|
//
|
||
|
// Returns: Same as SetClipboard
|
||
|
//
|
||
|
// Algorithm: If SetClipboardData succeeds, stop tracking the handle
|
||
|
//
|
||
|
// History: 30-Mar-94 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" HANDLE WINAPI UtSetClipboardData(UINT uFormat, HANDLE hMem)
|
||
|
{
|
||
|
HANDLE hRet;
|
||
|
|
||
|
hRet = SetClipboardData(uFormat, hMem);
|
||
|
|
||
|
if (NULL != hRet)
|
||
|
{
|
||
|
gGlobalTrack.cgtStopTracking(hMem);
|
||
|
}
|
||
|
|
||
|
return(hRet);
|
||
|
}
|
||
|
|
||
|
#endif // DBG==1 && defined(WIN32)
|