windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/orkin/memallo.cpp
2020-09-26 16:20:57 +08:00

1165 lines
30 KiB
C++

/*************************************************************************
* *
* MEMALLO.C *
* *
* Copyright (C) Microsoft Corporation 1990-1992 *
* All Rights reserved. *
* *
**************************************************************************
* *
* Module Intent *
* Debugging memory management module. The purpose of this module is *
* to ensure that memories are allocated, locked, unlocked and freed *
* properly. The following examples show some common mistakes, which *
* may cause havoc, and are hard to find: *
* - Use LocalFree() instead GlobalFree() for a global memory, and *
* vice versa. This bug will cause subtle error and possible system *
* crashes *
* - Lock or free garbage handle: will cause random system crashes *
* - Check for unfreed memory *
* *
* Note: All the local memory management scheme have been removed *
* - Since it will not work for DLL (using DS of the DLL instead *
* of the app *
* - There is plan to not to use local memory (to avoid 64K limit) *
**************************************************************************
* *
* Current Owner: BinhN *
* *
*************************************************************************/
#include <mvopsys.h>
#ifdef _DEBUG // {
#include <misc.h>
#include <mem.h>
#include <iterror.h>
#include "critsec.h"
#if !defined( MOSMEM ) // {
typedef struct tagMEMPOOL
{
HANDLE hnd;
DWORD size;
char FAR *lszFileName;
UINT line;
} MEMPOOL;
// Under multitasking Win32, protect debug functions by critical section
// We only protect simultaneous ALLOC & FREE. Lock and Unlock are not
// protected against each other because these cases are not supposed to happen
static CCriticalSection gcsMemory;
#define ENTER_CRITICAL_SECTION EnterCriticalSection(gcsMemory)
#define LEAVE_CRITICAL_SECTION LeaveCriticalSection(gcsMemory)
// make sure it is near to allow multiple instances
// for static case
static MEMPOOL FAR *GlobalPool=NULL;
static UINT GlobalPoolIndex = 0;
static UINT GlobalPoolSize=0;
static DWORD GlobalMemUsed = 0;
/*************************************************************************
*
* GLOBAL FUNCTIONS
*************************************************************************/
PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalAlloc(UINT, DWORD, LPSTR, UINT);
PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalReAlloc(HANDLE, DWORD,
UINT, LPSTR, UINT);
PUBLIC LPVOID EXPORT_API PASCAL FAR _GlobalLock(HANDLE, LPSTR, UINT);
PUBLIC int EXPORT_API PASCAL FAR _GlobalUnlock(HANDLE, LPSTR, UINT);
PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalFree(HANDLE, LPSTR, UINT);
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func VOID NEAR PASCAL | MakeGlobalPool |
* Just break inside CodeView
*************************************************************************/
PUBLIC VOID EXPORT_API PASCAL FAR MakeGlobalPool (void)
{
GlobalPool = (MEMPOOL FAR *)GlobalAllocPtr(DLLGMEM_ZEROINIT,
sizeof(MEMPOOL)*2000);
GlobalPoolSize = 2000;
GlobalMemUsed = 0;
GlobalPoolIndex = 0;
}
PUBLIC VOID EXPORT_API PASCAL FAR FreeGlobalPool (void)
{
if (GlobalPool)
GlobalFreePtr (GlobalPool);
GlobalPool = NULL;
GlobalPoolSize = 0;
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func int NEAR PASCAL | MemErr |
* Output the error
*
* @parm int | err |
* Error code
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Corresponding error
*************************************************************************/
int NEAR PASCAL MemErr(int err, LPSTR lszFilename, UINT line)
{
char Buffer[510];
switch (err)
{
case E_NOHANDLE:
wsprintf (Buffer, "No memory handle left. File: %s, line:%d\n",
lszFilename, line);
break;
case E_OUTOFMEMORY:
wsprintf (Buffer, "Out of memory. File: %s, line:%d\n",
lszFilename, line);
break;
case E_HANDLE:
wsprintf (Buffer, "Invalid handle. File: %s, line:%d\n",
lszFilename, line);
break;
case E_INVALIDARG:
wsprintf (Buffer, "Free locked handle. File: %s, line:%d\n",
lszFilename, line);
break;
case E_ASSERT:
wsprintf (Buffer, "Releasing invalid handle. File: %s, line:%d\n",
lszFilename, line);
break;
case E_FAIL:
wsprintf (Buffer, "Buffer overwritten. File: %s, line:%d\n",
lszFilename, line);
break;
case S_OK:
// wsprintf (Buffer, "Buffer > 64K. File: %s, line:%d\n",
// lszFilename, line);
return err;
break;
}
OutputDebugString (Buffer);
return(err);
}
void DumpMemory (void)
{
register UINT i;
char szTemp[1024];
ENTER_CRITICAL_SECTION;
/* Check in global memory pool */
for (i = 0; i <= GlobalPoolIndex; i++)
{
wsprintf(szTemp, "%u\t\t%s\t%u\n",
GlobalPool[i].size,
GlobalPool[i].lszFileName,
GlobalPool[i].line);
OutputDebugString(szTemp);
}
LEAVE_CRITICAL_SECTION;
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func UINT NEAR PASCAL | CheckMemValidity |
* Make sure that we really did allocate the specified handle
*
* @parm HANDLE | hnd |
* Handle to be checked
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc GlobalPoolSize + 1 if invalid handle, else the
* index of the pool location
*************************************************************************/
PRIVATE UINT NEAR PASCAL CheckMemValidity (HANDLE hnd, LPSTR lszFilename,
UINT line)
{
register UINT i;
// erinfox: critical section around this function because _GlobalLock
// and _GlobalUnlock use it
ENTER_CRITICAL_SECTION;
/* Check in global memory pool */
for (i = 0; i <= GlobalPoolIndex; i++)
{
if (GlobalPool[i].hnd == hnd)
{
LEAVE_CRITICAL_SECTION;
return i;
}
}
// if i is GlobalPoolSize, handle isn't truly "invalid" - it's
// just not part of the pool (because we've filled the pool)
if (i < GlobalPoolSize)
MemErr (E_HANDLE, lszFilename, line);
LEAVE_CRITICAL_SECTION;
return i;
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func HANDLE PASCAL | _GlobalAlloc |
* Allocate a near block of memory via GlobalAlloc. The number of
* handles is actually limited by GlobalPoolSize
*
* @parm UINT | flag |
* Various windows memory flags (such as GMEM_ZEROINIT)
*
* @parm DWORD | size |
* Size of the block
*
* @parm LPSTR | lpszFile |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Handle to the block of memory if succeded, 0 otherwise
*************************************************************************/
PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalAlloc(UINT flag, DWORD size,
LPSTR lszFilename, UINT line)
{
register UINT i, j;
MEMPOOL FAR *pMem = NULL;
#if 0
BYTE HUGE *lpb;
#endif
HANDLE hnd;
ENTER_CRITICAL_SECTION;
if (GlobalPool==NULL)
MakeGlobalPool();
/* Find an available handle */
for (i = 0; i < GlobalPoolSize; i++)
{
if (GlobalPool[i].hnd == 0)
{
pMem = &GlobalPool[i];
break;
}
}
if (pMem == NULL)
{
LEAVE_CRITICAL_SECTION;
MemErr (E_NOHANDLE, lszFilename, line);
return GlobalAlloc(flag, size);
}
/* Update index */
if (GlobalPoolIndex < i)
GlobalPoolIndex = i;
if ((hnd = GlobalAlloc(flag, size + 1)) == NULL)
{
LEAVE_CRITICAL_SECTION;
MemErr(E_OUTOFMEMORY, lszFilename, line);
return(NULL);
}
#if 0
/* Add buffer overflow checking */
if (lpb = GlobalLock (hnd))
{
*(lpb + size) = 'x';
GlobalUnlock (hnd);
}
#endif
/* Check to see if any other location has the same handle
* If happens since we may return a handle back to the user,
* who will eventually free it without our knowledge
*/
for (j = 0; j <= GlobalPoolIndex; j++)
{
if (j == i)
continue;
if (GlobalPool[j].hnd == hnd)
{
if (GlobalPool[j].size == (DWORD)-1)
break; // Reuse that "released" block
else
MemErr (E_ASSERT, lszFilename, line);
pMem = &GlobalPool[j];
}
}
pMem->hnd = hnd;
pMem->size = size;
pMem->lszFileName = lszFilename;
pMem->line = line;
GlobalMemUsed += size;
LEAVE_CRITICAL_SECTION;
return (pMem->hnd);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func HANDLE PASCAL | _GlobalReAlloc |
* Allocate a near block of memory via GlobalReAlloc. The function
* makes sure that we did allocate the memory block
*
* @parm HANDLE | handle |
* Handle to memory block
*
* @parm DWORD | size |
* Size of the block
*
* @parm WORD | flag |
* Various windows memory flags (such as GMEM_ZEROINIT)
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Return the new handle, or 0 if failed
*************************************************************************/
PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalReAlloc(HANDLE handle,
DWORD size, UINT flag, LPSTR lszFilename, UINT line)
{
register UINT i;
MEMPOOL FAR *pMem = NULL;
ENTER_CRITICAL_SECTION;
for (i = 0; i <= GlobalPoolIndex; i++)
{
if (GlobalPool[i].hnd == handle)
{
pMem = &GlobalPool[i];
break;
}
}
if (pMem == NULL)
{
LEAVE_CRITICAL_SECTION;
MemErr(E_HANDLE, lszFilename, line);
return GlobalReAlloc(handle, size, flag);
}
if (size) {
#if 0
BYTE HUGE *lpb;
if (pMem->size < size)
{
/* We have to remove the last 'x' that we put in */
lpb = GlobalLock (pMem->hnd);
lpb [pMem->size] = 0;
GlobalUnlock (pMem->hnd);
}
#endif
GlobalMemUsed += size - pMem->size;
pMem->size = size;
if ((pMem->hnd = GlobalReAlloc(handle, size + 1, flag)) == NULL)
MemErr(E_OUTOFMEMORY, lszFilename, line);
#if 0
if (lpb = GlobalLock (pMem->hnd))
{
*(lpb + size) = 'x';
GlobalUnlock (pMem->hnd);
}
#endif
}
else
{
if ((pMem->hnd = GlobalReAlloc(handle, size, flag)) == NULL)
MemErr(E_OUTOFMEMORY, lszFilename, line);
}
pMem->lszFileName = lszFilename;
pMem->line = line;
LEAVE_CRITICAL_SECTION;
return (pMem->hnd);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func LPVOID PASCAL FAR | _GlobalLock |
* Lock a piece of far memory via GlobalLock
*
* @parm HANDLE | hnd |
* Memory handle to be locked
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Pointer to the block of memory if succeeded, else NULL
*************************************************************************/
PUBLIC LPVOID EXPORT_API PASCAL FAR _GlobalLock(HANDLE hnd,
LPSTR lszFilename, UINT line)
{
if (hnd == 0)
{
// GarrG - removed call to MemErr. Locking a NULL handle
// is a valid thing to try, since it eliminates the necessity
// of checking for NULL twice (on the handle AND on the
// result of GlobalLock).
return NULL;
}
/* Check for data integrity */
CheckMemValidity(hnd, lszFilename, line);
return (LPVOID)GlobalLock(hnd);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func DWORD PASCAL FAR | _GlobalSize |
* Return the size of a block of memory
*
* @parm HANDLE | hnd |
* Handle to memory block
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Size of the block of memory
*************************************************************************/
PUBLIC DWORD EXPORT_API PASCAL FAR _GlobalSize(HANDLE hnd,
LPSTR lszFilename, UINT line)
{
UINT i;
if (hnd == 0)
{
MemErr(E_HANDLE, lszFilename, line);
return 0;
}
/* Check for data integrity */
if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
{
MemErr(E_HANDLE, lszFilename, line);
return (DWORD) GlobalSize(hnd);
}
return (GlobalPool[i].size);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func int PASCAL | _GlobalUnlock |
* Unlock a handle. Memory validity is checked for invalid handle
*
* @parm HANDLE | hnd |
* Handle to be unlocked
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc If the handle is valid, return GlobalUnlock(), else -1.
* In case of failure the returned value has not much validity
*************************************************************************/
PUBLIC int EXPORT_API PASCAL FAR _GlobalUnlock(HANDLE hnd,
LPSTR lszFilename, UINT line)
{
#if 0
BYTE HUGE *lpb;
#endif
register UINT i;
MEMPOOL FAR *pMem;
if (hnd == 0)
{
MemErr(E_HANDLE, lszFilename, line);
return -1;
}
/* Check for data integrity */
if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
{
return(GlobalUnlock(hnd));
}
pMem = &GlobalPool[i];
/* Now check for buffer overflow. This only works for memory allocated
* by us, ie. not through _GlobalAdd(), which in this case, has the
* size = -1
*/
#if 0
if (pMem->size != (DWORD)-1)
{
if (lpb = GlobalLock (hnd))
{
if (*(lpb + pMem->size) != 'x')
MemErr(E_FAIL, lszFilename, line);
GlobalUnlock(hnd);
}
}
#endif
return GlobalUnlock(hnd);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func HANDLE PASCAL | _GlobalFree |
* Free the global memory. Memory validity is checked to ensure that
* we don't free an invalid handle
*
* @parm HANDLE | hnd |
* Handle to the global memory to be freed
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Return NULL if failed, else the handle
*************************************************************************/
PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalFree(HANDLE hnd,
LPSTR lszFilename, UINT line)
{
register UINT i;
HANDLE h;
int count;
if (hnd == 0)
{
MemErr(E_HANDLE, lszFilename, line);
return 0;
}
if (hnd == (HANDLE)-1)
DumpMemory();
ENTER_CRITICAL_SECTION;
/* Check for data integrity */
if ((i = (CheckMemValidity(hnd, lszFilename, line))) >= GlobalPoolSize)
{
MemErr (E_ASSERT, lszFilename, line);
return (GlobalFree(hnd));
}
if (GlobalPool[i].size == (DWORD)-1)
{
/* We are freeing a pointer passed to us from the user, who has
* the responsibility to free it. This may be a bug.
*/
// MemErr (E_ASSERT, lszFilename, line);
GlobalPool[i].size = 0;
}
if ((count = (GlobalFlags(hnd) & GMEM_LOCKCOUNT)) > 0)
{
/* Freeing locked handle */
MemErr(E_INVALIDARG, lszFilename, line);
while (count > 0)
{
GlobalUnlock (hnd);
count--;
}
}
h = GlobalFree(hnd);
GlobalMemUsed -= GlobalPool[i].size;
GlobalPool[i].size = 0;
GlobalPool[i].lszFileName = NULL;
GlobalPool[i].hnd = 0;
GlobalPool[i].line = 0;
LEAVE_CRITICAL_SECTION ;
return h ;
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func HANDLE PASCAL | _GlobalRelease |
* There are case when we allocated memory blocks in MV and return
* them to the user. It is the user's responsibility to free this
* block.In this case, all the memory allocations scheme can't apply.
* In the meantime, we still want to keep track of all memory
* allocation. So this routine will remove the handle from the
* memory pool without really releasing it. It just stops tracking
* that piece of memory
*
* @parm HANDLE | hnd |
* Handle to be released from the memory pool
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*************************************************************************/
HANDLE EXPORT_API PASCAL FAR _GlobalRelease (HANDLE hnd, LPSTR lszFilename,
UINT line)
{
register UINT i;
MEMPOOL FAR *pMem;
ENTER_CRITICAL_SECTION;
if (hnd == 0)
{
LEAVE_CRITICAL_SECTION;
MemErr(E_HANDLE, lszFilename, line);
return (hnd);
}
/* Check for data integrity */
if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
{
LEAVE_CRITICAL_SECTION;
MemErr(E_HANDLE, lszFilename, line);
return (hnd);
}
pMem = &GlobalPool[i];
#if 0
if (pMem->size != (DWORD)-1)
{
BYTE HUGE *lpb;
if (lpb = (LPSTR)GlobalLock (hnd))
{
if (lpb[pMem->size] == 'x')
lpb[pMem->size] = 0;
GlobalUnlock(hnd);
}
GlobalMemUsed -= pMem->size;
}
#endif
pMem->size = 0;
pMem->lszFileName = NULL;
pMem->hnd = 0;
pMem->line = 0;
LEAVE_CRITICAL_SECTION;
return(hnd);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func EXPORT_API FAR PASCAL | _GlobalAdd |
* There are case when we receive a handle from the user to be
* manipulated (lock, unlock) etc. To make it works with our
* memory scheme, we need to put this into the memory table to be
* able to track it.
*
* @parm HANDLE | hnd |
* Handle to be added to the memory pool
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*************************************************************************/
HANDLE EXPORT_API PASCAL FAR _GlobalAdd (HANDLE hnd, LPSTR lszFilename,
UINT line)
{
register UINT i;
UINT j = (UINT)-1;
MEMPOOL FAR *pMem = NULL;
ENTER_CRITICAL_SECTION;
if (GlobalPool==NULL)
MakeGlobalPool();
/* Find an available handle */
for (i = 0; i < GlobalPoolSize; i++)
{
if (GlobalPool[i].hnd == 0)
{
if (j == (UINT)-1)
j = i;
}
else if (GlobalPool[i].hnd == hnd)
{
LEAVE_CRITICAL_SECTION;
return hnd; // Already in the pool
}
}
if (j == (UINT)-1)
{
LEAVE_CRITICAL_SECTION;
MemErr (E_NOHANDLE, lszFilename, line);
return NULL;
}
if (GlobalPoolIndex < j)
GlobalPoolIndex = j;
pMem = &GlobalPool[j];
pMem->size = (DWORD)-1; // Mark that the buffer came from outside
pMem->lszFileName = lszFilename;
pMem->line = line;
pMem->hnd = hnd;
LEAVE_CRITICAL_SECTION;
return hnd;
}
PUBLIC DWORD EXPORT_API PASCAL FAR GetMemUsed()
{
return GlobalMemUsed;
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func DWORD PASCAL | CheckMem |
* Make sure that all memory blocks are freed properly
*
* @rdesc Number of unfreed bytes
*************************************************************************/
PUBLIC DWORD EXPORT_API PASCAL FAR CheckMem()
{
register UINT i;
DWORD dwUnreleasedMem = 0;
HANDLE hnd;
char Buffer[500]; // 100 is not safe when filenames are real long.
LPSTR szFile ;
if ((GlobalMemUsed) == 0) {
FreeGlobalPool();
return 0;
}
if (GlobalPool) // When called several times, protect against null ptr
{
for (i = 0; i <= GlobalPoolIndex; i++)
{
if ((hnd = GlobalPool[i].hnd) && GlobalPool[i].size != (DWORD)-1)
{ // This pool is not released
dwUnreleasedMem += GlobalPool[i].size;
#ifdef WIN32
// When the DLL containing the string has been unloaded, we run into big troubles -> check
if (GlobalPool[i].lszFileName && !IsBadStringPtr(GlobalPool[i].lszFileName, sizeof(Buffer)/2))
szFile = GlobalPool[i].lszFileName ;
else
szFile = "File Unavailable" ;
#else // dunno if this would work on other platforms...
szFile = GlobalPool[i].lszFileName ;
#endif
wsprintf (Buffer,
"Unreleased GM at: %d, Size: %ld, Alloc at: %s, Line: %d\r\n",
i, GlobalPool[i].size, szFile,
GlobalPool[i].line);
OutputDebugString (Buffer);
/* Release the pool */
GlobalPool[i].hnd = 0;
GlobalUnlock(hnd);
GlobalFree(hnd);
}
}
}
else
dwUnreleasedMem = GlobalMemUsed ;
GlobalPoolIndex = 0;
FreeGlobalPool();
return dwUnreleasedMem;
}
#ifndef _MAC // {
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func HANDLE PASCAL | _VirtualAlloc |
* Allocate a block of memory via VirtualAlloc. The number of
* handles is actually limited by GlobalPoolSize
*
* @parm LPVOID | lpAddr |
* Address of region to be allocated
*
* @parm DWORD | size |
* Size of the block
*
* @parm DWORD | flag |
* Type of allocation
*
* @parm DWORD | fProtect |
* Type of access protection
*
* @parm LPSTR | lpszFile |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Handle to the block of memory if succeded, 0 otherwise
*************************************************************************/
PUBLIC HANDLE EXPORT_API PASCAL FAR _VirtualAlloc(LPVOID lpAddr, DWORD size,
DWORD flag, DWORD fProtect, LPSTR lszFilename, UINT line)
{
register UINT i, j;
MEMPOOL FAR *pMem = NULL;
#if 0
BYTE HUGE *lpb;
#endif
HANDLE hnd;
ENTER_CRITICAL_SECTION;
if (GlobalPool==NULL)
MakeGlobalPool();
/* Find an available handle */
for (i = 0; i < GlobalPoolSize; i++)
{
if (GlobalPool[i].hnd == 0)
{
pMem = &GlobalPool[i];
break;
}
}
if (pMem == NULL)
{
LEAVE_CRITICAL_SECTION;
MemErr (E_NOHANDLE, lszFilename, line);
return (HANDLE)VirtualAlloc(NULL, size, flag, fProtect);
}
/* Update index */
if (GlobalPoolIndex < i)
GlobalPoolIndex = i;
if ((hnd = (HANDLE)VirtualAlloc(NULL, size,
flag, fProtect)) == NULL)
{
MemErr(E_OUTOFMEMORY, lszFilename, line);
return(NULL);
}
/* Check to see if any other location has the same handle
* If happens since we may return a handle back to the user,
* who will eventually free it without our knowledge
*/
for (j = 0; j <= GlobalPoolIndex; j++)
{
if (j == i)
continue;
if (GlobalPool[j].hnd == hnd)
{
if (GlobalPool[j].size == (DWORD)-1)
break; // Reuse that "released" block
else
MemErr (E_ASSERT, lszFilename, line);
pMem = &GlobalPool[j];
}
}
pMem->hnd = hnd;
pMem->size = size;
pMem->lszFileName = lszFilename;
pMem->line = line;
GlobalMemUsed += size;
LEAVE_CRITICAL_SECTION;
return (pMem->hnd);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func LPVOID PASCAL FAR | __VirtualLock |
* Lock a piece of far memory via VirtualLock
*
* @parm HANDLE | hnd |
* Memory handle to be locked
*
* @parm DWORD | size |
* Size of memory to be locked
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Pointer to the block of memory if succeeded, else NULL
*************************************************************************/
PUBLIC LPVOID EXPORT_API PASCAL FAR _VirtualLock(HANDLE hnd, DWORD size,
LPSTR lszFilename, UINT line)
{
if (hnd == 0)
{
// GarrG - removed call to MemErr. Locking a NULL handle
// is a valid thing to try, since it eliminates the necessity
// of checking for NULL twice (on the handle AND on the
// result of VirtualLock).
return NULL;
}
/* Check for data integrity */
CheckMemValidity(hnd, lszFilename, line);
return (LPVOID)(VirtualLock(hnd, size) ? &hnd : NULL);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func int PASCAL | _VirtualUnlock |
* Unlock a handle. Memory validity is checked for invalid handle
*
* @parm HANDLE | hnd |
* Handle to be unlocked
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc If the handle is valid, return VirtualUnlock(), else -1.
* In case of failure the returned value has not much validity
*************************************************************************/
PUBLIC int EXPORT_API PASCAL FAR _VirtualUnlock(HANDLE hnd,
DWORD size, LPSTR lszFilename, UINT line)
{
#if 0
BYTE HUGE *lpb;
#endif
register UINT i;
MEMPOOL FAR *pMem;
if (hnd == 0)
{
MemErr(E_HANDLE, lszFilename, line);
return -1;
}
/* Check for data integrity */
if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
{
return(GlobalUnlock(hnd));
}
pMem = &GlobalPool[i];
/* Now check for buffer overflow. This only works for memory allocated
* by us, ie. not through _GlobalAdd(), which in this case, has the
* size = -1
*/
#if 0
if (pMem->size != (DWORD)-1)
{
if (lpb = GlobalLock (hnd))
{
if (*(lpb + pMem->size) != 'x')
MemErr(E_FAIL, lszFilename, line);
GlobalUnlock(hnd);
}
}
#endif
return VirtualUnlock(hnd, size);
}
/*************************************************************************
* @doc INTERNAL DEBUG
*
* @func int PASCAL | _VirtualFree |
* Free the global memory. Memory validity is checked to ensure that
* we don't free an invalid handle
*
* @parm HANDLE | hnd |
* Handle to the global memory to be freed
*
* @parm LPSTR | lszFilename |
* Module where the function is invoked
*
* @parm UINT | line |
* Line where the function is invoked
*
* @rdesc Return NULL if failed, else the handle
*************************************************************************/
PUBLIC int EXPORT_API PASCAL FAR _VirtualFree(HANDLE hnd, DWORD size,
DWORD flag, LPSTR lszFilename, UINT line)
{
register UINT i;
int h;
if (hnd == 0)
{
MemErr(E_HANDLE, lszFilename, line);
return 0;
}
/* Check for data integrity */
if ((i = (CheckMemValidity(hnd, lszFilename, line))) >= GlobalPoolSize)
{
MemErr (E_ASSERT, lszFilename, line);
return (VirtualFree(hnd, 0L, (MEM_DECOMMIT | MEM_RELEASE)));
}
ENTER_CRITICAL_SECTION;
h = VirtualFree(hnd, 0L, MEM_DECOMMIT | MEM_RELEASE);
GlobalMemUsed -= GlobalPool[i].size;
GlobalPool[i].size = 0;
GlobalPool[i].lszFileName = NULL;
GlobalPool[i].hnd = 0;
GlobalPool[i].line = 0;
LEAVE_CRITICAL_SECTION ;
return h ;
}
#endif // } _MAC
#else // }{
/****************************************************
*
* STUBS FOR NON-DEBUG VERSION TO SATISFY MVFS.DEF
*
****************************************************/
PUBLIC HANDLE PASCAL FAR _GlobalAlloc(UINT flag, DWORD size,
LPSTR lszFile, UINT line)
{
return GlobalAlloc(flag, size);
}
PUBLIC HANDLE PASCAL FAR _GlobalReAlloc(HANDLE handle,
DWORD size, UINT flag, LPSTR lszFile, UINT line)
{
return GlobalReAlloc(handle, size, flag);
}
PUBLIC LPVOID PASCAL FAR _GlobalLock(HANDLE hnd, LPSTR lszFile, UINT line)
{
return (LPVOID)GlobalLock(hnd);
}
PUBLIC int PASCAL FAR _GlobalUnlock(HANDLE hnd, LPSTR lszFile, UINT line)
{
return GlobalUnlock(hnd);
}
PUBLIC HANDLE PASCAL FAR _GlobalFree(HANDLE hnd, LPSTR lszFile, UINT line)
{
return GlobalFree(hnd);
}
PUBLIC DWORD PASCAL FAR _GlobalSize(HANDLE hnd, LPSTR lszFile, UINT line)
{
return GlobalSize(hnd);
}
PUBLIC int PASCAL FAR _GlobalAdd (HANDLE hnd, LPSTR lszFilename,
UINT line)
{
return(S_OK);
}
PUBLIC HANDLE PASCAL FAR _GlobalRelease (HANDLE hnd, LPSTR pszFilename,
UINT line)
{
return(hnd);
}
DWORD PASCAL EXPORT_API FAR GetMemUsed()
{
return 0;
}
DWORD PASCAL EXPORT_API FAR CheckMem()
{
return 0;
}
#ifndef _MAC // {_MAC
PUBLIC HANDLE EXPORT_API PASCAL FAR _VirtualAlloc(LPVOID lpv,
DWORD size, DWORD flag, DWORD fProtect, LPSTR lszFilename, UINT line)
{
return (HANDLE)VirtualAlloc(lpv, size, flag, fProtect);
}
PUBLIC LPVOID EXPORT_API PASCAL FAR _VirtualLock(HANDLE hnd, DWORD size,
LPSTR lszFilename, UINT line)
{
return (LPVOID)VirtualLock(hnd, size);
}
PUBLIC int EXPORT_API PASCAL FAR _VirtualUnlock(HANDLE hnd,
DWORD size, LPSTR lszFilename, UINT line)
{
return (int)VirtualUnlock(hnd, size);
}
PUBLIC int EXPORT_API PASCAL FAR _VirtualFree(HANDLE hnd, DWORD size,
DWORD flag, LPSTR lszFilename, UINT line)
{
return (VirtualFree(hnd, 0L, (MEM_DECOMMIT | MEM_RELEASE)));
}
#endif // }_MAC
#endif // }
#endif // } _DEBUG