|
|
/*************************************************************************
* * * 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
|