1193 lines
31 KiB
C
1193 lines
31 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atom.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the Win32 Global Memory Management APIs
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 24-Sep-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "basedll.h"
|
|
#pragma hdrstop
|
|
|
|
#include "winuserp.h"
|
|
#include "wowuserp.h"
|
|
|
|
PFNWOWGLOBALFREEHOOK pfnWowGlobalFreeHook = NULL;
|
|
|
|
VOID
|
|
WINAPI
|
|
RegisterWowBaseHandlers(
|
|
PFNWOWGLOBALFREEHOOK pfn)
|
|
{
|
|
pfnWowGlobalFreeHook = pfn;
|
|
}
|
|
|
|
|
|
#if i386
|
|
#pragma optimize("y",off)
|
|
#endif
|
|
|
|
HGLOBAL
|
|
WINAPI
|
|
GlobalAlloc(
|
|
UINT uFlags,
|
|
DWORD dwBytes
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
HANDLE hMem;
|
|
LPSTR p;
|
|
ULONG Flags;
|
|
|
|
if (uFlags & ~GMEM_VALID_FLAGS) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return( NULL );
|
|
}
|
|
|
|
Flags = 0;
|
|
if (uFlags & GMEM_ZEROINIT) {
|
|
Flags |= HEAP_ZERO_MEMORY;
|
|
}
|
|
|
|
if (!(uFlags & GMEM_MOVEABLE)) {
|
|
if (uFlags & GMEM_DDESHARE) {
|
|
Flags |= BASE_HEAP_FLAG_DDESHARE;
|
|
}
|
|
|
|
p = RtlAllocateHeap( BaseHeap,
|
|
MAKE_TAG( GMEM_TAG ) | Flags,
|
|
dwBytes ? dwBytes : 1
|
|
);
|
|
|
|
if (p == NULL) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
p = NULL;
|
|
RtlLockHeap( BaseHeap );
|
|
Flags |= HEAP_NO_SERIALIZE | HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVEABLE;
|
|
try {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)RtlAllocateHandle( &BaseHeapHandleTable, NULL );
|
|
if (HandleEntry == NULL) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto Fail;
|
|
}
|
|
|
|
hMem = (HANDLE)&HandleEntry->Object;
|
|
if (dwBytes != 0) {
|
|
p = (LPSTR)RtlAllocateHeap( BaseHeap, MAKE_TAG( GMEM_TAG ) | Flags, dwBytes );
|
|
if (p == NULL) {
|
|
HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
|
|
RtlFreeHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry );
|
|
HandleEntry = NULL;
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
else {
|
|
RtlSetUserValueHeap( BaseHeap, HEAP_NO_SERIALIZE, p, hMem );
|
|
}
|
|
}
|
|
Fail: ;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
if (HandleEntry != NULL) {
|
|
HandleEntry->Object = p;
|
|
if (p != NULL) {
|
|
HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
|
|
}
|
|
else {
|
|
HandleEntry->Flags = RTL_HANDLE_ALLOCATED | BASE_HANDLE_DISCARDED;
|
|
}
|
|
|
|
if (uFlags & GMEM_DISCARDABLE) {
|
|
HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
|
|
}
|
|
|
|
if (uFlags & GMEM_MOVEABLE) {
|
|
HandleEntry->Flags |= BASE_HANDLE_MOVEABLE;
|
|
}
|
|
|
|
if (uFlags & GMEM_DDESHARE) {
|
|
HandleEntry->Flags |= BASE_HANDLE_SHARED;
|
|
}
|
|
|
|
p = (LPSTR)hMem;
|
|
}
|
|
|
|
return( (HANDLE)p );
|
|
}
|
|
|
|
|
|
HGLOBAL
|
|
WINAPI
|
|
GlobalReAlloc(
|
|
HANDLE hMem,
|
|
DWORD dwBytes,
|
|
UINT uFlags
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
HANDLE Handle;
|
|
LPSTR p;
|
|
ULONG Flags;
|
|
|
|
if ((uFlags & ~(GMEM_VALID_FLAGS | GMEM_MODIFY)) ||
|
|
((uFlags & GMEM_DISCARDABLE) && !(uFlags & GMEM_MODIFY))
|
|
) {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalReAlloc( %lx ) - invalid flags\n", uFlags );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return( NULL );
|
|
}
|
|
|
|
Flags = 0;
|
|
if (uFlags & GMEM_ZEROINIT) {
|
|
Flags |= HEAP_ZERO_MEMORY;
|
|
}
|
|
if (!(uFlags & GMEM_MOVEABLE)) {
|
|
Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
|
|
}
|
|
|
|
RtlLockHeap( BaseHeap );
|
|
Flags |= HEAP_NO_SERIALIZE;
|
|
try {
|
|
if ((ULONG)hMem & BASE_HANDLE_MARK_BIT) {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)
|
|
CONTAINING_RECORD( hMem, BASE_HANDLE_TABLE_ENTRY, Object );
|
|
|
|
if (!RtlIsValidHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry )) {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalReAlloc( %lx ) - invalid handle\n", hMem );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
hMem = NULL;
|
|
}
|
|
else
|
|
if (uFlags & GMEM_MODIFY) {
|
|
if (uFlags & GMEM_DISCARDABLE) {
|
|
HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
|
|
}
|
|
else {
|
|
HandleEntry->Flags &= ~BASE_HANDLE_DISCARDABLE;
|
|
}
|
|
}
|
|
else {
|
|
p = HandleEntry->Object;
|
|
if (dwBytes == 0) {
|
|
hMem = NULL;
|
|
if (p != NULL) {
|
|
if ((uFlags & GMEM_MOVEABLE) && HandleEntry->LockCount == 0) {
|
|
if (RtlFreeHeap( BaseHeap, Flags, p )) {
|
|
HandleEntry->Object = NULL;
|
|
HandleEntry->Flags |= BASE_HANDLE_DISCARDED;
|
|
hMem = (HANDLE)&HandleEntry->Object;
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalReAlloc( %lx ) - failing with locked handle\n", &HandleEntry->Object );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
hMem = (HANDLE)&HandleEntry->Object;
|
|
}
|
|
}
|
|
else {
|
|
Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVEABLE;
|
|
if (p == NULL) {
|
|
p = RtlAllocateHeap( BaseHeap, MAKE_TAG( GMEM_TAG ) | Flags, dwBytes );
|
|
if (p != NULL) {
|
|
RtlSetUserValueHeap( BaseHeap, HEAP_NO_SERIALIZE, p, hMem );
|
|
}
|
|
}
|
|
else {
|
|
if (!(uFlags & GMEM_MOVEABLE) &&
|
|
HandleEntry->LockCount != 0
|
|
) {
|
|
Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
|
|
}
|
|
else {
|
|
Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
|
|
}
|
|
|
|
p = RtlReAllocateHeap( BaseHeap, MAKE_TAG( GMEM_TAG ) | Flags, p, dwBytes );
|
|
}
|
|
|
|
if (p != NULL) {
|
|
HandleEntry->Object = p;
|
|
HandleEntry->Flags &= ~BASE_HANDLE_DISCARDED;
|
|
}
|
|
else {
|
|
hMem = NULL;
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (uFlags & GMEM_MODIFY) {
|
|
if (uFlags & GMEM_MOVEABLE) {
|
|
Handle = hMem;
|
|
if (RtlGetUserInfoHeap( BaseHeap, HEAP_NO_SERIALIZE, (PVOID)hMem, &Handle, NULL )) {
|
|
if (Handle == hMem || !(Flags & BASE_HEAP_FLAG_MOVEABLE)) {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)RtlAllocateHandle( &BaseHeapHandleTable,
|
|
NULL
|
|
);
|
|
if (HandleEntry == NULL) {
|
|
hMem = NULL;
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
else {
|
|
dwBytes = RtlSizeHeap( BaseHeap, HEAP_NO_SERIALIZE, hMem );
|
|
Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVEABLE;
|
|
HandleEntry->Object = (PVOID)RtlAllocateHeap( BaseHeap,
|
|
MAKE_TAG( GMEM_TAG ) | Flags,
|
|
dwBytes
|
|
);
|
|
if (HandleEntry->Object == NULL) {
|
|
HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
|
|
RtlFreeHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry );
|
|
hMem = NULL;
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
else {
|
|
RtlMoveMemory( HandleEntry->Object, hMem, dwBytes );
|
|
RtlFreeHeap( BaseHeap, HEAP_NO_SERIALIZE, hMem );
|
|
hMem = (HANDLE)&HandleEntry->Object;
|
|
HandleEntry->LockCount = 0;
|
|
HandleEntry->Flags = RTL_HANDLE_ALLOCATED | BASE_HANDLE_MOVEABLE;
|
|
if (uFlags & GMEM_DISCARDABLE) {
|
|
HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
|
|
}
|
|
|
|
if ((ULONG)Handle & GMEM_DDESHARE) {
|
|
HandleEntry->Flags |= BASE_HANDLE_SHARED;
|
|
}
|
|
|
|
RtlSetUserValueHeap( BaseHeap,
|
|
HEAP_NO_SERIALIZE,
|
|
HandleEntry->Object,
|
|
hMem
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
hMem = RtlReAllocateHeap( BaseHeap,
|
|
MAKE_TAG( GMEM_TAG ) | Flags | HEAP_NO_SERIALIZE,
|
|
(PVOID)hMem,
|
|
dwBytes
|
|
);
|
|
if (hMem == NULL) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
hMem = NULL;
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
return( (LPSTR)hMem );
|
|
}
|
|
|
|
LPVOID
|
|
WINAPI
|
|
GlobalLock(
|
|
HGLOBAL hMem
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
LPSTR p;
|
|
|
|
if ((ULONG)hMem & BASE_HANDLE_MARK_BIT) {
|
|
RtlLockHeap( BaseHeap );
|
|
try {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)
|
|
CONTAINING_RECORD( hMem, BASE_HANDLE_TABLE_ENTRY, Object );
|
|
|
|
if (!RtlIsValidHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry )) {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalLock( %lx ) - invalid handle\n", hMem );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
p = NULL;
|
|
}
|
|
else {
|
|
p = HandleEntry->Object;
|
|
if (p != NULL) {
|
|
if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT) {
|
|
HandleEntry->LockCount--;
|
|
}
|
|
}
|
|
else {
|
|
SetLastError( ERROR_DISCARDED );
|
|
}
|
|
}
|
|
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
p = NULL;
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
return( p );
|
|
}
|
|
else {
|
|
if ( (ULONG)hMem & 0x80000000 ) {
|
|
return NULL;
|
|
}
|
|
return( (LPSTR)hMem );
|
|
}
|
|
}
|
|
|
|
|
|
HANDLE
|
|
WINAPI
|
|
GlobalHandle(
|
|
LPCVOID pMem
|
|
)
|
|
{
|
|
HANDLE Handle;
|
|
ULONG Flags;
|
|
|
|
RtlLockHeap( BaseHeap );
|
|
try {
|
|
Handle = NULL;
|
|
if (!RtlGetUserInfoHeap( BaseHeap, HEAP_NO_SERIALIZE, (LPVOID)pMem, &Handle, &Flags )) {
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
}
|
|
else
|
|
if (Handle == NULL || !(Flags & BASE_HEAP_FLAG_MOVEABLE)) {
|
|
Handle = (HANDLE)pMem;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
return( Handle );
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GlobalUnlock(
|
|
HANDLE hMem
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
BOOL Result;
|
|
|
|
Result = TRUE;
|
|
if ((ULONG)hMem & BASE_HANDLE_MARK_BIT) {
|
|
RtlLockHeap( BaseHeap );
|
|
try {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)
|
|
CONTAINING_RECORD( hMem, BASE_HANDLE_TABLE_ENTRY, Object );
|
|
|
|
if (!RtlIsValidHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry )) {
|
|
#if DBG
|
|
PVOID ImageBase;
|
|
|
|
//
|
|
// If passed address is NOT part of an image file, then display
|
|
// a debug message. This prevents apps that call GlobalUnlock
|
|
// with the return value of LockResource from displaying the
|
|
// message.
|
|
//
|
|
|
|
if (!RtlPcToFileHeader( (PVOID)hMem, &ImageBase)) {
|
|
DbgPrint( "*** GlobalUnlock( %lx ) - invalid handle\n", hMem );
|
|
BaseHeapBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
}
|
|
else
|
|
if (HandleEntry->LockCount-- == 0) {
|
|
HandleEntry->LockCount++;
|
|
SetLastError( ERROR_NOT_LOCKED );
|
|
Result = FALSE;
|
|
}
|
|
else
|
|
if (HandleEntry->LockCount == 0) {
|
|
SetLastError( NO_ERROR );
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
}
|
|
|
|
return( Result );
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
GlobalSize(
|
|
HANDLE hMem
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
PVOID Handle;
|
|
ULONG Flags;
|
|
DWORD dwSize;
|
|
|
|
dwSize = 0xFFFFFFFF;
|
|
Flags = 0;
|
|
RtlLockHeap( BaseHeap );
|
|
try {
|
|
if (!((ULONG)hMem & BASE_HANDLE_MARK_BIT)) {
|
|
Handle = NULL;
|
|
if (!RtlGetUserInfoHeap( BaseHeap, Flags, hMem, &Handle, &Flags )) {
|
|
}
|
|
else
|
|
if (Handle == NULL || !(Flags & BASE_HEAP_FLAG_MOVEABLE)) {
|
|
dwSize = RtlSizeHeap( BaseHeap, HEAP_NO_SERIALIZE, (PVOID)hMem );
|
|
}
|
|
else {
|
|
hMem = Handle;
|
|
}
|
|
}
|
|
|
|
if ((ULONG)hMem & BASE_HANDLE_MARK_BIT) {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)
|
|
CONTAINING_RECORD( hMem, BASE_HANDLE_TABLE_ENTRY, Object );
|
|
|
|
if (!RtlIsValidHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry )) {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalSize( %lx ) - invalid handle\n", hMem );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
}
|
|
else
|
|
if (HandleEntry->Flags & BASE_HANDLE_DISCARDED) {
|
|
dwSize = HandleEntry->Size;
|
|
}
|
|
else {
|
|
dwSize = RtlSizeHeap( BaseHeap, HEAP_NO_SERIALIZE, HandleEntry->Object );
|
|
}
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
if (dwSize == 0xFFFFFFFF) {
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return 0;
|
|
}
|
|
else {
|
|
return dwSize;
|
|
}
|
|
}
|
|
|
|
UINT
|
|
WINAPI
|
|
GlobalFlags(
|
|
HANDLE hMem
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
HANDLE Handle;
|
|
ULONG Flags;
|
|
UINT uFlags;
|
|
|
|
uFlags = GMEM_INVALID_HANDLE;
|
|
RtlLockHeap( BaseHeap );
|
|
try {
|
|
if (!((ULONG)hMem & BASE_HANDLE_MARK_BIT)) {
|
|
Handle = NULL;
|
|
Flags = 0;
|
|
if (!RtlGetUserInfoHeap( BaseHeap, Flags, hMem, &Handle, &Flags )) {
|
|
}
|
|
else
|
|
if (Handle == NULL || !(Flags & BASE_HEAP_FLAG_MOVEABLE)) {
|
|
uFlags = 0;
|
|
}
|
|
else {
|
|
hMem = Handle;
|
|
}
|
|
}
|
|
|
|
if ((ULONG)hMem & BASE_HANDLE_MARK_BIT) {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)
|
|
CONTAINING_RECORD( hMem, BASE_HANDLE_TABLE_ENTRY, Object );
|
|
|
|
if (RtlIsValidHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry )) {
|
|
uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
|
|
if (HandleEntry->Flags & BASE_HANDLE_DISCARDED) {
|
|
uFlags |= GMEM_DISCARDED;
|
|
}
|
|
|
|
if (HandleEntry->Flags & BASE_HANDLE_DISCARDABLE) {
|
|
uFlags |= GMEM_DISCARDABLE;
|
|
}
|
|
|
|
if (HandleEntry->Flags & BASE_HANDLE_SHARED) {
|
|
uFlags |= GMEM_DDESHARE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uFlags == GMEM_INVALID_HANDLE) {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalFlags( %lx ) - invalid handle\n", hMem );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
return( uFlags );
|
|
}
|
|
|
|
|
|
HGLOBAL
|
|
WINAPI
|
|
GlobalFree(
|
|
HGLOBAL hMem
|
|
)
|
|
{
|
|
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
|
|
LPSTR p;
|
|
|
|
if (pfnWowGlobalFreeHook != NULL) {
|
|
if (!(*pfnWowGlobalFreeHook)(hMem)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (!((ULONG)hMem & BASE_HANDLE_MARK_BIT)) {
|
|
if (RtlFreeHeap( BaseHeap, 0, (PVOID)hMem )) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
return hMem;
|
|
}
|
|
}
|
|
|
|
RtlLockHeap( BaseHeap );
|
|
try {
|
|
if ((ULONG)hMem & BASE_HANDLE_MARK_BIT) {
|
|
HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)
|
|
CONTAINING_RECORD( hMem, BASE_HANDLE_TABLE_ENTRY, Object );
|
|
|
|
if (!RtlIsValidHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry )) {
|
|
#if DBG
|
|
DbgPrint( "*** GlobalFree( %lx ) - invalid handle\n", hMem );
|
|
BaseHeapBreakPoint();
|
|
#endif
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
p = NULL;
|
|
}
|
|
else {
|
|
#if DBG
|
|
if (HandleEntry->LockCount != 0) {
|
|
DbgPrint( "BASE: GlobalFree called with a locked object.\n" );
|
|
BaseHeapBreakPoint();
|
|
}
|
|
#endif
|
|
p = HandleEntry->Object;
|
|
RtlFreeHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry );
|
|
if (p == NULL) {
|
|
hMem = NULL;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
p = (LPSTR)hMem;
|
|
}
|
|
|
|
if (p != NULL) {
|
|
if (RtlFreeHeap( BaseHeap, HEAP_NO_SERIALIZE, p )) {
|
|
hMem = NULL;
|
|
}
|
|
else {
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
}
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
BaseSetLastNTError( GetExceptionCode() );
|
|
}
|
|
|
|
RtlUnlockHeap( BaseHeap );
|
|
|
|
return( hMem );
|
|
}
|
|
|
|
|
|
UINT
|
|
WINAPI
|
|
GlobalCompact(
|
|
DWORD dwMinFree
|
|
)
|
|
{
|
|
return RtlCompactHeap( BaseHeap, 0 );
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
GlobalFix(
|
|
HGLOBAL hMem
|
|
)
|
|
{
|
|
if (hMem != (HGLOBAL)-1) {
|
|
GlobalLock( hMem );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
GlobalUnfix(
|
|
HGLOBAL hMem
|
|
)
|
|
{
|
|
if (hMem != (HGLOBAL)-1) {
|
|
GlobalUnlock( hMem );
|
|
}
|
|
return;
|
|
}
|
|
|
|
LPVOID
|
|
WINAPI
|
|
GlobalWire(
|
|
HGLOBAL hMem
|
|
)
|
|
{
|
|
return GlobalLock( hMem );
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
GlobalUnWire(
|
|
HGLOBAL hMem
|
|
)
|
|
{
|
|
return GlobalUnlock( hMem );
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
GlobalMemoryStatus(
|
|
LPMEMORYSTATUS lpBuffer
|
|
)
|
|
{
|
|
|
|
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
|
|
VM_COUNTERS VmCounters;
|
|
QUOTA_LIMITS QuotaLimits;
|
|
DWORD AvailPageFile;
|
|
DWORD PhysicalMemory;
|
|
NTSTATUS Status;
|
|
|
|
Status = NtQuerySystemInformation(
|
|
SystemPerformanceInformation,
|
|
&PerfInfo,
|
|
sizeof(PerfInfo),
|
|
NULL
|
|
);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages * BaseStaticServerData->SysInfo.PageSize;
|
|
|
|
lpBuffer->dwLength = sizeof( *lpBuffer );
|
|
|
|
//
|
|
// Determine the memory load. < 100 available pages is 100
|
|
// > 1100 available pages is 0
|
|
//
|
|
|
|
if (PerfInfo.AvailablePages < 100) {
|
|
lpBuffer->dwMemoryLoad = 100;
|
|
} else {
|
|
(long)lpBuffer->dwMemoryLoad = 100 - (long)((PerfInfo.AvailablePages - 100) / 10);
|
|
if ((long)lpBuffer->dwMemoryLoad < 0) {
|
|
lpBuffer->dwMemoryLoad = 0;
|
|
}
|
|
}
|
|
|
|
lpBuffer->dwTotalPhys = PhysicalMemory;
|
|
|
|
PhysicalMemory = PerfInfo.AvailablePages;
|
|
PhysicalMemory *= BaseStaticServerData->SysInfo.PageSize;
|
|
|
|
lpBuffer->dwAvailPhys = PhysicalMemory;
|
|
|
|
//
|
|
// Zero returned values in case the query process fails.
|
|
//
|
|
|
|
RtlZeroMemory (&QuotaLimits, sizeof (QUOTA_LIMITS));
|
|
RtlZeroMemory (&VmCounters, sizeof (VM_COUNTERS));
|
|
|
|
Status = NtQueryInformationProcess (NtCurrentProcess(),
|
|
ProcessQuotaLimits,
|
|
&QuotaLimits,
|
|
sizeof(QUOTA_LIMITS),
|
|
NULL );
|
|
|
|
Status = NtQueryInformationProcess (NtCurrentProcess(),
|
|
ProcessVmCounters,
|
|
&VmCounters,
|
|
sizeof(VM_COUNTERS),
|
|
NULL );
|
|
//
|
|
// Determine the total page file space with respect to this process.
|
|
//
|
|
|
|
lpBuffer->dwTotalPageFile = PerfInfo.CommitLimit;
|
|
if (QuotaLimits.PagefileLimit < PerfInfo.CommitLimit) {
|
|
lpBuffer->dwTotalPageFile = QuotaLimits.PagefileLimit;
|
|
}
|
|
|
|
lpBuffer->dwTotalPageFile *= BaseStaticServerData->SysInfo.PageSize;
|
|
|
|
//
|
|
// Determine remaining page file space with respect to this process.
|
|
//
|
|
|
|
AvailPageFile = PerfInfo.CommitLimit - PerfInfo.CommittedPages;
|
|
|
|
lpBuffer->dwAvailPageFile =
|
|
QuotaLimits.PagefileLimit - VmCounters.PagefileUsage;
|
|
|
|
if ((ULONG)lpBuffer->dwTotalPageFile > (ULONG)AvailPageFile) {
|
|
lpBuffer->dwAvailPageFile = AvailPageFile;
|
|
}
|
|
|
|
lpBuffer->dwAvailPageFile *= BaseStaticServerData->SysInfo.PageSize;
|
|
|
|
lpBuffer->dwTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress -
|
|
BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1;
|
|
|
|
lpBuffer->dwAvailVirtual = lpBuffer->dwTotalVirtual - VmCounters.VirtualSize;
|
|
return;
|
|
}
|
|
|
|
|
|
PVOID
|
|
WINAPI
|
|
VirtualAlloc(
|
|
PVOID lpAddress,
|
|
DWORD dwSize,
|
|
DWORD flAllocationType,
|
|
DWORD flProtect
|
|
)
|
|
{
|
|
|
|
return VirtualAllocEx(
|
|
NtCurrentProcess(),
|
|
lpAddress,
|
|
dwSize,
|
|
flAllocationType,
|
|
flProtect
|
|
);
|
|
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
VirtualFree(
|
|
LPVOID lpAddress,
|
|
DWORD dwSize,
|
|
DWORD dwFreeType
|
|
)
|
|
{
|
|
return VirtualFreeEx(NtCurrentProcess(),lpAddress,dwSize,dwFreeType);
|
|
}
|
|
|
|
PVOID
|
|
WINAPI
|
|
VirtualAllocEx(
|
|
HANDLE hProcess,
|
|
PVOID lpAddress,
|
|
DWORD dwSize,
|
|
DWORD flAllocationType,
|
|
DWORD flProtect
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (lpAddress != NULL && (ULONG)lpAddress < BaseStaticServerData->SysInfo.AllocationGranularity) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return( NULL );
|
|
}
|
|
|
|
try {
|
|
Status = NtAllocateVirtualMemory( hProcess,
|
|
&lpAddress,
|
|
0,
|
|
&dwSize,
|
|
flAllocationType,
|
|
flProtect
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
return( lpAddress );
|
|
}
|
|
else {
|
|
BaseSetLastNTError( Status );
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
VirtualFreeEx(
|
|
HANDLE hProcess,
|
|
LPVOID lpAddress,
|
|
DWORD dwSize,
|
|
DWORD dwFreeType
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if ( (dwFreeType & MEM_RELEASE ) && dwSize != 0 ) {
|
|
BaseSetLastNTError( STATUS_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtFreeVirtualMemory( hProcess,
|
|
&lpAddress,
|
|
&dwSize,
|
|
dwFreeType
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
BaseSetLastNTError( Status );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
VirtualProtect(
|
|
PVOID lpAddress,
|
|
DWORD dwSize,
|
|
DWORD flNewProtect,
|
|
PDWORD lpflOldProtect
|
|
)
|
|
{
|
|
|
|
return VirtualProtectEx( NtCurrentProcess(),
|
|
lpAddress,
|
|
dwSize,
|
|
flNewProtect,
|
|
lpflOldProtect
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
VirtualProtectEx(
|
|
HANDLE hProcess,
|
|
PVOID lpAddress,
|
|
DWORD dwSize,
|
|
DWORD flNewProtect,
|
|
PDWORD lpflOldProtect
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = NtProtectVirtualMemory( hProcess,
|
|
&lpAddress,
|
|
&dwSize,
|
|
flNewProtect,
|
|
lpflOldProtect
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
return( TRUE );
|
|
}
|
|
else {
|
|
BaseSetLastNTError( Status );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
VirtualQuery(
|
|
LPCVOID lpAddress,
|
|
PMEMORY_BASIC_INFORMATION lpBuffer,
|
|
DWORD dwLength
|
|
)
|
|
{
|
|
|
|
return VirtualQueryEx( NtCurrentProcess(),
|
|
lpAddress,
|
|
(PMEMORY_BASIC_INFORMATION)lpBuffer,
|
|
dwLength
|
|
);
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
VirtualQueryEx(
|
|
HANDLE hProcess,
|
|
LPCVOID lpAddress,
|
|
PMEMORY_BASIC_INFORMATION lpBuffer,
|
|
DWORD dwLength
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ReturnLength;
|
|
|
|
Status = NtQueryVirtualMemory( hProcess,
|
|
(LPVOID)lpAddress,
|
|
MemoryBasicInformation,
|
|
(PMEMORY_BASIC_INFORMATION)lpBuffer,
|
|
dwLength,
|
|
&ReturnLength
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
return( ReturnLength );
|
|
}
|
|
else {
|
|
BaseSetLastNTError( Status );
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
VirtualLock(
|
|
LPVOID lpAddress,
|
|
DWORD dwSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API may be used to lock the specified range of the processes
|
|
address space into memory. This range is present whenever the
|
|
application is running. All pages covered by the range must be
|
|
commited. VirtialLock is in now way related to LocalLock or
|
|
GlobalLock. It does not perform a handle translation. Its function
|
|
is to lock memory in the "working set" of the calling process.
|
|
|
|
Note that the specified range is used to compute the range of pages
|
|
covered by the lock. A 2 byte lock that straddles a page boundry
|
|
ends up locking both of the pages covered by the range. Also note
|
|
that calls to VirtualLock do not nest.
|
|
|
|
|
|
Arguments:
|
|
|
|
lpAddress - Supplies the base address of the region being locked.
|
|
|
|
dwSize - Supplies the number of bytes being locked.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was was successful.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
ULONG RegionSize;
|
|
BOOL ReturnValue;
|
|
|
|
ReturnValue = TRUE;
|
|
BaseAddress = lpAddress;
|
|
RegionSize = dwSize;
|
|
|
|
Status = NtLockVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&lpAddress,
|
|
&RegionSize,
|
|
MAP_PROCESS
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
ReturnValue = FALSE;
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
VirtualUnlock(
|
|
LPVOID lpAddress,
|
|
DWORD dwSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API may be used to unlock the specified range of the processes
|
|
address space from memory. This call is used to reveres the effects of
|
|
a previous call to VirtualLock. The range specified need not match
|
|
a range passed to a previous VirtualLock call, but it must specify
|
|
a locked range" for this API to be successful.
|
|
|
|
Note that the specified range is used to compute the range of pages
|
|
covered by the unlock. A 2 byte unlock that straddles a page boundry
|
|
ends up unlocking both of the pages covered by the range.
|
|
|
|
Arguments:
|
|
|
|
lpAddress - Supplies the base address of the region being unlocked.
|
|
|
|
dwSize - Supplies the number of bytes being unlocked.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was was successful.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
ULONG RegionSize;
|
|
BOOL ReturnValue;
|
|
|
|
ReturnValue = TRUE;
|
|
BaseAddress = lpAddress;
|
|
RegionSize = dwSize;
|
|
|
|
Status = NtUnlockVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&lpAddress,
|
|
&RegionSize,
|
|
MAP_PROCESS
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
ReturnValue = FALSE;
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
FlushInstructionCache(
|
|
HANDLE hProcess,
|
|
LPCVOID lpBaseAddress,
|
|
DWORD dwSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function flushes the instruction cache for the specified process.
|
|
|
|
Arguments:
|
|
|
|
hProcess - Supplies a handle to the process in which the instruction
|
|
cache is to be flushed.
|
|
|
|
lpBaseAddress - Supplies an optional pointer to base of the region that
|
|
is flushed.
|
|
|
|
dwSize - Supplies the length of the region that is flushed if the base
|
|
address is specified.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The operation was was successful.
|
|
|
|
FALSE - The operation failed. Extended error status is available
|
|
using GetLastError.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
NTSTATUS Status;
|
|
BOOL ReturnValue = TRUE;
|
|
|
|
Status = NtFlushInstructionCache(
|
|
hProcess,
|
|
(LPVOID)lpBaseAddress,
|
|
dwSize
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
BaseSetLastNTError(Status);
|
|
ReturnValue = FALSE;
|
|
}
|
|
|
|
return ReturnValue;
|
|
|
|
}
|