windows-nt/Source/XPSP1/NT/base/win32/client/gmem.c
2020-09-26 16:20:57 +08:00

1584 lines
41 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
gmem.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"
#include <wow64t.h>
PFNWOWGLOBALFREEHOOK pfnWowGlobalFreeHook = NULL;
VOID
WINAPI
RegisterWowBaseHandlers(
PFNWOWGLOBALFREEHOOK pfn)
{
pfnWowGlobalFreeHook = pfn;
}
#if i386
#pragma optimize("y",off)
#endif
HGLOBAL
WINAPI
GlobalAlloc(
UINT uFlags,
SIZE_T 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,
SIZE_T 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_PTR)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_PTR)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_PTR)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_PTR)hMem >= SystemRangeStart ) {
SetLastError( ERROR_INVALID_HANDLE );
return NULL;
}
if (IsBadReadPtr( hMem, 1 )) {
SetLastError( ERROR_INVALID_HANDLE );
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_PTR)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 );
}
SIZE_T
WINAPI
GlobalSize(
HANDLE hMem
)
{
PBASE_HANDLE_TABLE_ENTRY HandleEntry;
PVOID Handle;
ULONG Flags;
SIZE_T dwSize;
dwSize = MAXULONG_PTR;
Flags = 0;
RtlLockHeap( BaseHeap );
try {
if (!((ULONG_PTR)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_PTR)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 == MAXULONG_PTR) {
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_PTR)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_PTR)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;
try {
if (pfnWowGlobalFreeHook != NULL) {
if (!(*pfnWowGlobalFreeHook)(hMem)) {
return NULL;
}
}
if (!((ULONG_PTR)hMem & BASE_HANDLE_MARK_BIT)) {
if (RtlFreeHeap( BaseHeap, 0, (PVOID)hMem )) {
return NULL;
}
else {
SetLastError( ERROR_INVALID_HANDLE );
return hMem;
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
BaseSetLastNTError( GetExceptionCode() );
return hMem;
}
RtlLockHeap( BaseHeap );
try {
if ((ULONG_PTR)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 );
}
SIZE_T
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
)
{
DWORD NumberOfPhysicalPages;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
VM_COUNTERS VmCounters;
QUOTA_LIMITS QuotaLimits;
NTSTATUS Status;
PPEB Peb;
PIMAGE_NT_HEADERS NtHeaders;
DWORDLONG Memory64;
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
ASSERT(NT_SUCCESS(Status));
lpBuffer->dwLength = sizeof( *lpBuffer );
//
// Capture the number of physical pages as it can change dynamically.
// If it goes up or down in the middle of this routine, the results may
// look strange (ie: available > total, etc), but it will quickly
// right itself.
//
NumberOfPhysicalPages = USER_SHARED_DATA->NumberOfPhysicalPages;
#if defined(BUILD_WOW6432)
//
// Convert the number of physical pages from the native system to
// the emulation system.
//
NumberOfPhysicalPages = NumberOfPhysicalPages * (Wow64GetSystemNativePageSize() / BASE_SYSINFO.PageSize);
#endif
//
// Determine the memory load. < 100 available pages is 100
// Otherwise load is ((TotalPhys - AvailPhys) * 100) / TotalPhys
//
if (PerfInfo.AvailablePages < 100) {
lpBuffer->dwMemoryLoad = 100;
}
else {
lpBuffer->dwMemoryLoad =
((DWORD)(NumberOfPhysicalPages - PerfInfo.AvailablePages) * 100) /
NumberOfPhysicalPages;
}
//
// Determine the physical memory sizes.
//
Memory64 = (DWORDLONG)NumberOfPhysicalPages * BASE_SYSINFO.PageSize;
lpBuffer->dwTotalPhys = (SIZE_T) __min(Memory64, MAXULONG_PTR);
Memory64 = ((DWORDLONG)PerfInfo.AvailablePages * (DWORDLONG)BASE_SYSINFO.PageSize);
lpBuffer->dwAvailPhys = (SIZE_T) __min(Memory64, MAXULONG_PTR);
if (gpTermsrvAdjustPhyMemLimits) {
gpTermsrvAdjustPhyMemLimits(&(lpBuffer->dwTotalPhys),
&(lpBuffer->dwAvailPhys),
BASE_SYSINFO.PageSize);
}
//
// 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.
//
Memory64 = __min(PerfInfo.CommitLimit, QuotaLimits.PagefileLimit);
Memory64 *= BASE_SYSINFO.PageSize;
lpBuffer->dwTotalPageFile = (SIZE_T)__min(Memory64, MAXULONG_PTR);
//
// Determine remaining page file space with respect to this process.
//
Memory64 = __min(PerfInfo.CommitLimit - PerfInfo.CommittedPages,
QuotaLimits.PagefileLimit - VmCounters.PagefileUsage);
Memory64 *= BASE_SYSINFO.PageSize;
lpBuffer->dwAvailPageFile = (SIZE_T) __min(Memory64, MAXULONG_PTR);
lpBuffer->dwTotalVirtual = (BASE_SYSINFO.MaximumUserModeAddress -
BASE_SYSINFO.MinimumUserModeAddress) + 1;
lpBuffer->dwAvailVirtual = lpBuffer->dwTotalVirtual - VmCounters.VirtualSize;
#if !defined(_WIN64)
//
// Lie about available memory if application can't handle large (>2GB) addresses
//
Peb = NtCurrentPeb();
NtHeaders = RtlImageNtHeader( Peb->ImageBaseAddress );
if (NtHeaders && !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) {
if (lpBuffer->dwTotalPhys > 0x7FFFFFFF) {
lpBuffer->dwTotalPhys = 0x7FFFFFFF;
}
if (lpBuffer->dwAvailPhys > 0x7FFFFFFF) {
lpBuffer->dwAvailPhys = 0x7FFFFFFF;
}
if (lpBuffer->dwTotalVirtual > 0x7FFFFFFF) {
lpBuffer->dwTotalVirtual = 0x7FFFFFFF;
}
if (lpBuffer->dwAvailVirtual > 0x7FFFFFFF) {
lpBuffer->dwAvailVirtual = 0x7FFFFFFF;
}
}
#endif
return;
}
PVOID
WINAPI
VirtualAlloc(
PVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
)
{
return VirtualAllocEx(
NtCurrentProcess(),
lpAddress,
dwSize,
flAllocationType,
flProtect
);
}
BOOL
WINAPI
VirtualFree(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD dwFreeType
)
{
return VirtualFreeEx(NtCurrentProcess(),lpAddress,dwSize,dwFreeType);
}
PVOID
WINAPI
VirtualAllocEx(
HANDLE hProcess,
PVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
)
{
NTSTATUS Status;
if (lpAddress != NULL && (ULONG_PTR)lpAddress < BASE_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,
SIZE_T 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 {
if (Status == STATUS_INVALID_PAGE_PROTECTION) {
if (hProcess == NtCurrentProcess()) {
//
// Unlock any pages that were locked with MmSecureVirtualMemory.
// This is useful for SANs.
//
if (RtlFlushSecureMemoryCache(lpAddress, dwSize)) {
Status = NtFreeVirtualMemory( hProcess,
&lpAddress,
&dwSize,
dwFreeType
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
}
}
}
BaseSetLastNTError( Status );
return( FALSE );
}
}
BOOL
WINAPI
VirtualProtect(
PVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
)
{
return VirtualProtectEx( NtCurrentProcess(),
lpAddress,
dwSize,
flNewProtect,
lpflOldProtect
);
}
BOOL
WINAPI
VirtualProtectEx(
HANDLE hProcess,
PVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
)
{
NTSTATUS Status;
Status = NtProtectVirtualMemory( hProcess,
&lpAddress,
&dwSize,
flNewProtect,
lpflOldProtect
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
if (Status == STATUS_INVALID_PAGE_PROTECTION) {
if (hProcess == NtCurrentProcess()) {
//
// Unlock any pages that were locked with MmSecureVirtualMemory.
// This is useful for SANs.
//
if (RtlFlushSecureMemoryCache(lpAddress, dwSize)) {
Status = NtProtectVirtualMemory( hProcess,
&lpAddress,
&dwSize,
flNewProtect,
lpflOldProtect
);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
}
}
}
BaseSetLastNTError( Status );
return( FALSE );
}
}
SIZE_T
WINAPI
VirtualQuery(
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
)
{
return VirtualQueryEx( NtCurrentProcess(),
lpAddress,
(PMEMORY_BASIC_INFORMATION)lpBuffer,
dwLength
);
}
SIZE_T
WINAPI
VirtualQueryEx(
HANDLE hProcess,
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
)
{
NTSTATUS Status;
SIZE_T 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,
SIZE_T 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;
SIZE_T 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,
SIZE_T 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;
SIZE_T 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,
SIZE_T 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;
}
BOOL
WINAPI
AllocateUserPhysicalPages(
HANDLE hProcess,
PULONG_PTR NumberOfPages,
PULONG_PTR PageArray
)
{
NTSTATUS Status;
Status = NtAllocateUserPhysicalPages( hProcess,
NumberOfPages,
PageArray);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
BaseSetLastNTError( Status );
return( FALSE );
}
}
BOOL
WINAPI
FreeUserPhysicalPages(
HANDLE hProcess,
PULONG_PTR NumberOfPages,
PULONG_PTR PageArray
)
{
NTSTATUS Status;
Status = NtFreeUserPhysicalPages( hProcess,
NumberOfPages,
PageArray);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
BaseSetLastNTError( Status );
return( FALSE );
}
}
BOOL
WINAPI
MapUserPhysicalPages(
PVOID VirtualAddress,
ULONG_PTR NumberOfPages,
PULONG_PTR PageArray
)
{
NTSTATUS Status;
Status = NtMapUserPhysicalPages( VirtualAddress,
NumberOfPages,
PageArray);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
BaseSetLastNTError( Status );
return( FALSE );
}
}
BOOL
WINAPI
MapUserPhysicalPagesScatter(
PVOID *VirtualAddresses,
ULONG_PTR NumberOfPages,
PULONG_PTR PageArray
)
{
NTSTATUS Status;
Status = NtMapUserPhysicalPagesScatter( VirtualAddresses,
NumberOfPages,
PageArray);
if (NT_SUCCESS( Status )) {
return( TRUE );
}
else {
BaseSetLastNTError( Status );
return( FALSE );
}
}
BOOL
WINAPI
GlobalMemoryStatusEx(
LPMEMORYSTATUSEX lpBuffer
)
{
DWORD NumberOfPhysicalPages;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
VM_COUNTERS VmCounters;
QUOTA_LIMITS QuotaLimits;
DWORDLONG AvailPageFile;
DWORDLONG PhysicalMemory;
NTSTATUS Status;
DWORD Success;
DWORDLONG address64;
if (lpBuffer->dwLength != sizeof(*lpBuffer)) {
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
ASSERT(NT_SUCCESS(Status));
//
// Capture the number of physical pages as it can change dynamically.
// If it goes up or down in the middle of this routine, the results may
// look strange (ie: available > total, etc), but it will quickly
// right itself.
//
NumberOfPhysicalPages = USER_SHARED_DATA->NumberOfPhysicalPages;
#if defined(BUILD_WOW6432)
//
// Convert the number of physical pages from the native system to
// the emulation system.
//
NumberOfPhysicalPages = NumberOfPhysicalPages * (Wow64GetSystemNativePageSize() / BASE_SYSINFO.PageSize);
#endif
PhysicalMemory = (DWORDLONG)NumberOfPhysicalPages * BASE_SYSINFO.PageSize;
//
// Determine the memory load. < 100 available pages is 100
// Otherwise load is ((TotalPhys - AvailPhys) * 100) / TotalPhys
//
if (PerfInfo.AvailablePages < 100) {
lpBuffer->dwMemoryLoad = 100;
}
else {
lpBuffer->dwMemoryLoad =
((DWORD)(NumberOfPhysicalPages - PerfInfo.AvailablePages) * 100) /
NumberOfPhysicalPages;
}
lpBuffer->ullTotalPhys = PhysicalMemory;
PhysicalMemory = PerfInfo.AvailablePages;
PhysicalMemory *= BASE_SYSINFO.PageSize;
lpBuffer->ullAvailPhys = 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->ullTotalPageFile = PerfInfo.CommitLimit;
if (QuotaLimits.PagefileLimit < PerfInfo.CommitLimit) {
lpBuffer->ullTotalPageFile = QuotaLimits.PagefileLimit;
}
lpBuffer->ullTotalPageFile *= BASE_SYSINFO.PageSize;
//
// Determine remaining page file space with respect to this process.
//
AvailPageFile = PerfInfo.CommitLimit - PerfInfo.CommittedPages;
lpBuffer->ullAvailPageFile =
QuotaLimits.PagefileLimit - VmCounters.PagefileUsage;
if ((ULONG)lpBuffer->ullAvailPageFile > (ULONG)AvailPageFile) {
lpBuffer->ullAvailPageFile = AvailPageFile;
}
lpBuffer->ullAvailPageFile *= BASE_SYSINFO.PageSize;
lpBuffer->ullTotalVirtual = (BASE_SYSINFO.MaximumUserModeAddress -
BASE_SYSINFO.MinimumUserModeAddress) + 1;
lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual - VmCounters.VirtualSize;
lpBuffer->ullAvailExtendedVirtual = 0;
return TRUE;
}
WINBASEAPI
UINT
WINAPI
GetWriteWatch(
DWORD dwFlags,
PVOID lpBaseAddress,
SIZE_T dwRegionSize,
PVOID *addresses,
ULONG_PTR *count,
LPDWORD granularity
)
{
NTSTATUS Status;
Status = NtGetWriteWatch ( NtCurrentProcess(),
dwFlags,
lpBaseAddress,
dwRegionSize,
addresses,
count,
granularity
);
//
// Note these return codes are taken straight from Win9x.
//
if (NT_SUCCESS( Status )) {
return( 0 );
}
else {
BaseSetLastNTError( Status );
return (UINT)-1;
}
}
WINBASEAPI
UINT
WINAPI
ResetWriteWatch(
LPVOID lpBaseAddress,
SIZE_T dwRegionSize
)
{
NTSTATUS Status;
Status = NtResetWriteWatch ( NtCurrentProcess(),
lpBaseAddress,
dwRegionSize
);
//
// Note these return codes are taken straight from Win9x.
//
if (NT_SUCCESS( Status )) {
return( 0 );
}
else {
BaseSetLastNTError( Status );
return (UINT)-1;
}
}