+++ /dev/null
-/*
- * PROJECT: ReactOS Win32 Base API
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: dll/win32/kernel32/client/heapmem.c
- * PURPOSE: Heap Memory APIs (wrappers for RtlHeap*)
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES *******************************************************************/
-
-#include <k32.h>
-
-#define NDEBUG
-#include <debug.h>
-
-/* GLOBALS ********************************************************************/
-
-RTL_HANDLE_TABLE BaseHeapHandleTable;
-HANDLE BaseHeap;
-ULONG_PTR SystemRangeStart;
-
-/* PRIVATE FUNCTIONS **********************************************************/
-
-VOID
-NTAPI
-BaseDllInitializeMemoryManager(VOID)
-{
- BaseHeap = RtlGetProcessHeap();
- RtlInitializeHandleTable(0xFFFF,
- sizeof(BASE_HEAP_HANDLE_ENTRY),
- &BaseHeapHandleTable);
- NtQuerySystemInformation(SystemRangeStartInformation,
- &SystemRangeStart,
- sizeof(SystemRangeStart),
- NULL);
-}
-
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-HeapCreate(DWORD flOptions,
- SIZE_T dwInitialSize,
- SIZE_T dwMaximumSize)
-{
- HANDLE hRet;
- ULONG Flags;
-
- /* Remove non-Win32 flags and tag this allocation */
- Flags = (flOptions & (HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE)) |
- HEAP_CLASS_1;
-
- /* Check if heap is growable and ensure max size is correct */
- if (dwMaximumSize == 0)
- Flags |= HEAP_GROWABLE;
- else if (dwMaximumSize < BaseStaticServerData->SysInfo.PageSize &&
- dwInitialSize > dwMaximumSize)
- {
- /* Max size is non-zero but less than page size which can't be correct.
- Fix it up by bumping it to the initial size whatever it is. */
- dwMaximumSize = dwInitialSize;
- }
-
- /* Call RTL Heap */
- hRet = RtlCreateHeap(Flags,
- NULL,
- dwMaximumSize,
- dwInitialSize,
- NULL,
- NULL);
-
- /* Set the last error if we failed, and return the pointer */
- if (!hRet) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return hRet;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapDestroy(HANDLE hHeap)
-{
- /* Return TRUE if the heap was destroyed */
- if (!RtlDestroyHeap(hHeap)) return TRUE;
-
- /* Otherwise, we got the handle back, so fail */
- SetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
-}
-
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-GetProcessHeap(VOID)
-{
- /* Call the RTL API */
- return RtlGetProcessHeap();
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-GetProcessHeaps(DWORD NumberOfHeaps,
- PHANDLE ProcessHeaps)
-{
- /* Call the RTL API */
- return RtlGetProcessHeaps(NumberOfHeaps, ProcessHeaps);
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapLock(HANDLE hHeap)
-{
- /* Call the RTL API */
- return RtlLockHeap(hHeap);
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapUnlock(HANDLE hHeap)
-{
- /* Call the RTL API */
- return RtlUnlockHeap(hHeap);
-}
-
-/*
- * @implemented
- */
-SIZE_T
-WINAPI
-HeapCompact(HANDLE hHeap, DWORD dwFlags)
-{
- /* Call the RTL API */
- return RtlCompactHeap(hHeap, dwFlags);
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapValidate(HANDLE hHeap,
- DWORD dwFlags,
- LPCVOID lpMem)
-{
- /* Call the RTL API */
- return RtlValidateHeap(hHeap, dwFlags, (PVOID)lpMem);
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-HeapCreateTagsW(HANDLE hHeap,
- DWORD dwFlags,
- PWSTR lpTagName,
- PWSTR lpTagSubName)
-{
- /* Call the RTL API */
- return RtlCreateTagHeap(hHeap,
- dwFlags,
- lpTagName,
- lpTagSubName);
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-HeapExtend(HANDLE hHeap,
- DWORD dwFlags,
- PVOID BaseAddress,
- DWORD dwBytes)
-{
- NTSTATUS Status;
-
- /* Call the RTL API. Gone in Vista, so commented out. */
- Status = STATUS_NOT_IMPLEMENTED; //RtlExtendHeap(hHeap, dwFlags, BaseAddress, dwBytes);
- if (!NT_SUCCESS(Status))
- {
- /* We failed */
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* Return success */
- return TRUE;
-}
-
-/*
- * @implemented
- */
-PWSTR
-WINAPI
-HeapQueryTagW(HANDLE hHeap,
- DWORD dwFlags,
- WORD wTagIndex,
- BOOL bResetCounters,
- PVOID lpTagInfo)
-{
- /* Call the RTL API */
- return RtlQueryTagHeap(hHeap,
- dwFlags,
- wTagIndex,
- (BOOLEAN)bResetCounters,
- lpTagInfo);
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapSummary(HANDLE hHeap,
- DWORD dwFlags,
- PVOID Summary)
-{
- NTSTATUS Status;
- RTL_HEAP_USAGE Usage;
-
- /* Fill in the length information */
- Usage.Length = sizeof(Usage);
-
- /* Call RTL. Gone in Vista, so commented out */
- Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage);
- if (!NT_SUCCESS(Status))
- {
- /* We failed */
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* FIXME: Summary == Usage?! */
- RtlCopyMemory(Summary, &Usage, sizeof(Usage));
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapUsage(HANDLE hHeap,
- DWORD dwFlags,
- DWORD Unknown,
- DWORD Unknown2,
- IN PVOID Usage)
-{
- NTSTATUS Status;
-
- /* Call RTL. Gone in Vista, so commented out */
- Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage);
- if (!NT_SUCCESS(Status))
- {
- /* We failed */
- BaseSetLastNTError(Status);
- return FALSE;
- }
- else if (Status == STATUS_MORE_ENTRIES)
- {
- /* There are still more entries to parse */
- return TRUE;
- }
-
- /* Otherwise, we're completely done, so we return FALSE, but NO_ERROR */
- SetLastError(NO_ERROR);
- return FALSE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapWalk(HANDLE hHeap,
- LPPROCESS_HEAP_ENTRY lpEntry)
-{
- NTSTATUS Status;
-
- DPRINT1("Warning, HeapWalk is calling RtlWalkHeap with Win32 parameters\n");
-
- Status = RtlWalkHeap(hHeap, lpEntry);
-
- if (!NT_SUCCESS(Status))
- {
- SetLastError(RtlNtStatusToDosError(Status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapQueryInformation(HANDLE HeapHandle,
- HEAP_INFORMATION_CLASS HeapInformationClass,
- PVOID HeapInformation OPTIONAL,
- SIZE_T HeapInformationLength OPTIONAL,
- PSIZE_T ReturnLength OPTIONAL)
-{
- NTSTATUS Status;
-
- Status = RtlQueryHeapInformation(HeapHandle,
- HeapInformationClass,
- HeapInformation,
- HeapInformationLength,
- ReturnLength);
-
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-HeapSetInformation(HANDLE HeapHandle,
- HEAP_INFORMATION_CLASS HeapInformationClass,
- PVOID HeapInformation OPTIONAL,
- SIZE_T HeapInformationLength OPTIONAL)
-{
- NTSTATUS Status;
-
- Status = RtlSetHeapInformation(HeapHandle,
- HeapInformationClass,
- HeapInformation,
- HeapInformationLength);
-
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-HGLOBAL
-NTAPI
-GlobalAlloc(UINT uFlags,
- SIZE_T dwBytes)
-{
- ULONG Flags = 0;
- PVOID Ptr = NULL;
- HANDLE hMemory;
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- BASE_TRACE_ALLOC(dwBytes, uFlags);
- ASSERT(BaseHeap);
-
- /* Make sure the flags are valid */
- if (uFlags & ~GMEM_VALID_FLAGS)
- {
- /* They aren't, fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
- }
-
- /* Convert ZEROINIT */
- if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
-
- /* Check if we're not movable, which means pointer-based heap */
- if (!(uFlags & GMEM_MOVEABLE))
- {
- /* Check if this is DDESHARE (deprecated) */
- if (uFlags & GMEM_DDESHARE) Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
-
- /* Allocate heap for it */
- Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes ? dwBytes : 1);
- if (!Ptr) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- BASE_TRACE_ALLOC2(Ptr);
- return Ptr;
- }
-
- /* This is heap based, so lock it in first */
- RtlLockHeap(BaseHeap);
-
- /*
- * Disable locking, enable custom flags, and write the
- * movable flag (deprecated)
- */
- Flags |= HEAP_NO_SERIALIZE |
- HEAP_SETTABLE_USER_VALUE |
- BASE_HEAP_FLAG_MOVABLE;
-
- /* Allocate the handle */
- HandleEntry = BaseHeapAllocEntry();
- if (!HandleEntry)
- {
- /* Fail */
- hMemory = NULL;
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- BASE_TRACE_FAILURE();
- }
- else
- {
- /* Get the object and make sure we have size */
- hMemory = &HandleEntry->Object;
- if (dwBytes)
- {
- /* Allocate the actual memory for it */
- Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
- BASE_TRACE_PTR(HandleEntry, Ptr);
- if (!Ptr)
- {
- /* We failed, manually set the allocate flag and free the handle */
- HandleEntry->Flags = RTL_HANDLE_VALID;
- BaseHeapFreeEntry(HandleEntry);
-
- /* For the cleanup case */
- HandleEntry = NULL;
- }
- else
- {
- /* All worked well, save our heap entry */
- RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
- }
- }
- }
-
- /* Cleanup! First unlock the heap */
- RtlUnlockHeap(BaseHeap);
-
- /* Check if a handle was allocated */
- if (HandleEntry)
- {
- /* Set the pointer and allocated flag */
- HandleEntry->Object = Ptr;
- HandleEntry->Flags = RTL_HANDLE_VALID;
- if (!Ptr)
- {
- /* We don't have a valid pointer, but so reuse this handle */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
- }
-
- /* Check if the handle is discardable */
- if (uFlags & GMEM_DISCARDABLE)
- {
- /* Save it in the handle entry */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
-
- /* Check if the handle is moveable */
- if (uFlags & GMEM_MOVEABLE)
- {
- /* Save it in the handle entry */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
- }
-
- /* Check if the handle is DDE Shared */
- if (uFlags & GMEM_DDESHARE)
- {
- /* Save it in the handle entry */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
- }
-
- /* Set the pointer */
- Ptr = hMemory;
- }
-
- /* Return the pointer */
- return Ptr;
-}
-
-/*
- * @implemented
- */
-SIZE_T
-NTAPI
-GlobalCompact(DWORD dwMinFree)
-{
- /* Call the RTL Heap Manager */
- return RtlCompactHeap(BaseHeap, 0);
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-GlobalFix(HGLOBAL hMem)
-{
- /* Lock the memory if it the handle is valid */
- if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem);
-}
-
-/*
- * @implemented
- */
-UINT
-NTAPI
-GlobalFlags(HGLOBAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- HANDLE Handle = NULL;
- ULONG Flags = 0;
- UINT uFlags = GMEM_INVALID_HANDLE;
-
- /* Start by locking the heap */
- RtlLockHeap(BaseHeap);
- _SEH2_TRY
- {
- /* Check if this is a simple RTL Heap Managed block */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Then we'll query RTL Heap */
- RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
- BASE_TRACE_PTR(Handle, hMem);
-
- /*
- * Check if RTL Heap didn't find a handle associated with us or
- * said that this heap isn't movable, which means something we're
- * really not a handle-based heap.
- */
- if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
- {
- /* Then set the flags to 0 */
- uFlags = 0;
- }
- else
- {
- /* Otherwise we're handle-based, so get the internal handle */
- hMem = Handle;
- }
- }
-
- /* Check if the handle is actually an entry in our table */
- if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
- {
- /* Then get the entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure it's a valid handle */
- if (BaseHeapValidateEntry(HandleEntry))
- {
- /* Get the lock count first */
- uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
-
- /* Now check if it's discardable */
- if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
- {
- /* Set the Win32 Flag */
- uFlags |= GMEM_DISCARDABLE;
- }
-
- /* Check if it's DDE Shared */
- if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_DDESHARE)
- {
- /* Set the Win32 Flag */
- uFlags |= GMEM_DDESHARE;
- }
-
- /* Now check if it's discarded */
- if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
- {
- /* Set the Win32 Flag */
- uFlags |= GMEM_DISCARDED;
- }
- }
- }
-
- /* Check if by now, we still haven't gotten any useful flags */
- if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Set the exception code */
- BaseSetLastNTError(_SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* All done! Unlock heap and return Win32 Flags */
- RtlUnlockHeap(BaseHeap);
- return uFlags;
-}
-
-/*
- * @implemented
- */
-HGLOBAL
-NTAPI
-GlobalFree(HGLOBAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- LPVOID Ptr;
- BASE_TRACE_DEALLOC(hMem);
-
- /* Check if this was a simple allocated heap entry */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Free it with the RTL Heap Manager */
- if (RtlFreeHeap(BaseHeap, 0, hMem))
- {
- /* Return NULL since there's no handle */
- return NULL;
- }
- else
- {
- /* Otherwise fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- return hMem;
- }
- }
-
- /* It's a handle probably, so lock the heap */
- RtlLockHeap(BaseHeap);
- _SEH2_TRY
- {
- /* Make sure that this is an entry in our handle database */
- if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
- {
- /* Get the entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure the handle is valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* It's not, fail */
- SetLastError(ERROR_INVALID_HANDLE);
- Ptr = NULL;
- }
- else
- {
- /* It's valid, so get the pointer */
- Ptr = HandleEntry->Object;
-
- /* Free this handle */
- BaseHeapFreeEntry(HandleEntry);
-
- /* If the pointer is 0, then we don't have a handle either */
- if (!Ptr) hMem = NULL;
- }
- }
- else
- {
- /* Otherwise, reuse the handle as a pointer */
- BASE_TRACE_FAILURE();
- Ptr = hMem;
- }
-
- /* Check if we got here with a valid heap pointer */
- if (Ptr)
- {
- /* Free it with the RTL Heap Manager */
- if (RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr))
- {
- /* Everything worked */
- hMem = NULL;
- }
- else
- {
- /* This wasn't a real heap handle */
- SetLastError(ERROR_INVALID_HANDLE);
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Set the exception code */
- BaseSetLastNTError(_SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* We're done, so unlock the heap and return the handle */
- RtlUnlockHeap(BaseHeap);
- return hMem;
-}
-
-/*
- * @implemented
- */
-HGLOBAL
-NTAPI
-GlobalHandle(LPCVOID pMem)
-{
- HANDLE Handle = NULL;
- ULONG Flags;
-
- /* Lock the heap */
- RtlLockHeap(BaseHeap);
- _SEH2_TRY
- {
- /* Query RTL Heap */
- if (!RtlGetUserInfoHeap(BaseHeap,
- HEAP_NO_SERIALIZE,
- (PVOID)pMem,
- &Handle,
- &Flags))
- {
- /* RTL Heap Manager does not know about this heap */
- SetLastError(ERROR_INVALID_HANDLE);
- }
- else
- {
- /*
- * Check if RTL Heap didn't find a handle for us or said that
- * this heap isn't movable.
- */
- BASE_TRACE_PTR(Handle, pMem);
- if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
- {
- /* We're actually handle-based, so the pointer is a handle */
- Handle = (HANDLE)pMem;
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Set the exception code */
- BaseSetLastNTError(_SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- /* All done, unlock the heap and return the handle */
- RtlUnlockHeap(BaseHeap);
- return Handle;
-}
-
-/*
- * @implemented
- */
-LPVOID
-NTAPI
-GlobalLock(HGLOBAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- LPVOID Ptr;
-
- /* Check if this was a simple allocated heap entry */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Make sure it's not a kernel or invalid address */
- if ((hMem >= (HGLOBAL)SystemRangeStart) || (IsBadReadPtr(hMem, 1)))
- {
- /* Signal an error */
- SetLastError(ERROR_INVALID_HANDLE);
- return NULL;
- }
-
- /* It's all good */
- return hMem;
- }
-
- /* Otherwise, lock the heap */
- RtlLockHeap(BaseHeap);
- _SEH2_TRY
- {
- /* Get the handle entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure it's valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* It's not, fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- Ptr = NULL;
- }
- else
- {
- /* Otherwise, get the pointer */
- Ptr = HandleEntry->Object;
- if (Ptr)
- {
- /* Increase the lock count, unless we've went too far */
- if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT)
- {
- /* In which case we simply unlock once */
- HandleEntry->LockCount--;
- }
- }
- else
- {
- /* The handle is still there but the memory was already freed */
- SetLastError(ERROR_DISCARDED);
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- SetLastError(ERROR_INVALID_HANDLE);
- Ptr = NULL;
- }
- _SEH2_END;
-
- /* All done. Unlock the heap and return the pointer */
- RtlUnlockHeap(BaseHeap);
- return Ptr;
-}
-
-HGLOBAL
-NTAPI
-GlobalReAlloc(HGLOBAL hMem,
- SIZE_T dwBytes,
- UINT uFlags)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- HANDLE Handle;
- LPVOID Ptr;
- ULONG Flags = 0;
-
- /* Throw out invalid flags */
- if (uFlags & ~(GMEM_VALID_FLAGS | GMEM_MODIFY))
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
- }
-
- /* Throw out invalid combo */
- if ((uFlags & GMEM_DISCARDABLE) && !(uFlags & GMEM_MODIFY))
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
- }
-
- /* Convert ZEROINIT */
- if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
-
- /* If this wasn't a movable heap, then we MUST re-alloc in place */
- if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
-
- /* Lock the heap and disable built-in locking in the RTL Heap functions */
- RtlLockHeap(BaseHeap);
- Flags |= HEAP_NO_SERIALIZE;
-
- /* Check if this is a simple handle-based block */
- if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Get the entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure the handle is valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* Fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- hMem = NULL;
- }
- else if (uFlags & GMEM_MODIFY)
- {
- /* User is changing flags... check if the memory was discardable */
- if (uFlags & GMEM_DISCARDABLE)
- {
- /* Then set the flag */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
- else
- {
- /* Otherwise, remove the flag */
- HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
- }
- else
- {
- /* Otherwise, get the object and check if we have no size */
- Ptr = HandleEntry->Object;
- if (!dwBytes)
- {
- /* Clear the handle and check for a pointer */
- hMem = NULL;
- if (Ptr)
- {
- /* Make sure the handle isn't locked */
- if ((uFlags & GMEM_MOVEABLE) && !(HandleEntry->LockCount))
- {
- /* Free the current heap */
- if (RtlFreeHeap(BaseHeap, Flags, Ptr))
- {
- /* Free the handle */
- HandleEntry->Object = NULL;
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
-
- /* Get the object pointer */
- hMem = &HandleEntry->Object;
- }
- }
- }
- else
- {
- /* Otherwise just return the object pointer */
- hMem = &HandleEntry->Object;
- }
- }
- else
- {
- /* Otherwise, we're allocating, so set the new flags needed */
- Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
- if (!Ptr)
- {
- /* We don't have a base, so allocate one */
- Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
- BASE_TRACE_ALLOC2(Ptr);
- if (Ptr)
- {
- /* Allocation succeeded, so save our entry */
- RtlSetUserValueHeap(BaseHeap,
- HEAP_NO_SERIALIZE,
- Ptr,
- hMem);
- }
- }
- else
- {
- /*
- * If it's not movable or currently locked, we MUST allocate
- * in-place!
- */
- if (!(uFlags & GMEM_MOVEABLE) && (HandleEntry->LockCount))
- {
- /* Set the flag */
- Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
- }
- else
- {
- /* Otherwise clear the flag if we set it previously */
- Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
- }
-
- /* Do the re-allocation. No need to save the entry again */
- Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
- }
-
- /* Make sure we have a pointer by now */
- if (Ptr)
- {
- /* Write it in the handle entry and mark it in use */
- HandleEntry->Object = Ptr;
- HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
- }
- else
- {
- /* Otherwise we failed */
- hMem = NULL;
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- }
- }
- }
- }
- else if (uFlags & GMEM_MODIFY)
- {
- /* This is not a handle-based heap and the caller wants it to be one */
- if (uFlags & GMEM_MOVEABLE)
- {
- /* Get information on its current state */
- Handle = hMem;
- if (RtlGetUserInfoHeap(BaseHeap,
- HEAP_NO_SERIALIZE,
- hMem,
- &Handle,
- NULL))
- {
- /*
- * Check if the handle matches the pointer or the moveable flag
- * isn't there, which is what we expect since it currently isn't.
- */
- if ((Handle == hMem) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
- {
- /* Allocate a handle for it */
- HandleEntry = BaseHeapAllocEntry();
- if (!HandleEntry)
- {
- /* No entry could be allocated */
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- RtlUnlockHeap(BaseHeap);
- return NULL;
- }
-
- /* Calculate the size of the current heap */
- dwBytes = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
-
- /* Set the movable flag */
- Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
-
- /* Now allocate the actual heap for it */
- HandleEntry->Object = RtlAllocateHeap(BaseHeap,
- Flags,
- dwBytes);
- BASE_TRACE_PTR(HandleEntry->Object, HandleEntry);
- if (!HandleEntry->Object)
- {
- /*
- * We failed, manually set the allocate flag and
- * free the handle
- */
- HandleEntry->Flags = RTL_HANDLE_VALID;
- BaseHeapFreeEntry(HandleEntry);
-
- /* For the cleanup case */
- BASE_TRACE_FAILURE();
- HandleEntry = NULL;
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- }
- else
- {
- /* Otherwise, copy the new heap and free the old one */
- RtlMoveMemory(HandleEntry->Object, hMem, dwBytes);
- RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
-
- /* Select the heap pointer */
- hMem = (HANDLE)&HandleEntry->Object;
-
- /* Initialize the count and default flags */
- HandleEntry->LockCount = 0;
- HandleEntry->Flags = RTL_HANDLE_VALID |
- BASE_HEAP_ENTRY_FLAG_MOVABLE;
-
- /* Check if it's also discardable */
- if (uFlags & GMEM_DISCARDABLE)
- {
- /* Set the internal flag */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
-
- /* Check if it's also DDE Shared */
- if (uFlags & GMEM_DDESHARE)
- {
- /* Set the internal flag */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
- }
-
- /* Allocation succeeded, so save our entry */
- RtlSetUserValueHeap(BaseHeap,
- HEAP_NO_SERIALIZE,
- HandleEntry->Object,
- hMem);
- }
- }
- }
- }
- }
- else
- {
- /* Otherwise, this is a simple RTL Managed Heap, so just call it */
- hMem = RtlReAllocateHeap(BaseHeap,
- Flags | HEAP_NO_SERIALIZE,
- hMem,
- dwBytes);
- if (!hMem)
- {
- /* Fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- }
- }
-
- /* All done, unlock the heap and return the pointer */
- RtlUnlockHeap(BaseHeap);
- return hMem;
-}
-
-/*
- * @implemented
- */
-SIZE_T
-NTAPI
-GlobalSize(HGLOBAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- PVOID Handle = NULL;
- ULONG Flags = 0;
- SIZE_T dwSize = MAXULONG_PTR;
-
- /* Lock the heap */
- RtlLockHeap(BaseHeap);
- _SEH2_TRY
- {
- /* Check if this is a simple RTL Heap Managed block */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Then we'll query RTL Heap */
- if (RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags))
- {
- BASE_TRACE_PTR(Handle, hMem);
- /*
- * Check if RTL Heap didn't give us a handle or said that this
- * heap isn't movable.
- */
- if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
- {
- /* We're not a handle heap, so use the generic call */
- dwSize = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
- }
- else
- {
- /* We're a handle heap so get the internal handle */
- hMem = Handle;
- }
- }
- }
-
- /* Make sure that this is an entry in our handle database */
- if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
- {
- /* Get the entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure the handle is valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* Fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- }
- else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
- {
- /* We've reused this block, but we've saved the size for you */
- dwSize = HandleEntry->OldSize;
- }
- else
- {
- /* Otherwise, query RTL about it */
- dwSize = RtlSizeHeap(BaseHeap,
- HEAP_NO_SERIALIZE,
- HandleEntry->Object);
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- /* Set failure for later */
- dwSize = MAXULONG_PTR;
- }
- _SEH2_END;
-
- /* Check if by now, we still haven't gotten any useful size */
- if (dwSize == MAXULONG_PTR)
- {
- /* Fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- dwSize = 0;
- }
-
- /* All done! Unlock heap and return the size */
- RtlUnlockHeap(BaseHeap);
- return dwSize;
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-GlobalUnfix(HGLOBAL hMem)
-{
- /* If the handle is valid, unlock it */
- if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem);
-}
-
-/*
- * @implemented
- */
-BOOL
-NTAPI
-GlobalUnlock(HGLOBAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- BOOL RetVal = TRUE;
-
- /* Check if this was a simple allocated heap entry */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) return RetVal;
-
- /* Otherwise, lock the heap */
- RtlLockHeap(BaseHeap);
-
- /* Get the handle entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- _SEH2_TRY
- {
- /* Make sure it's valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* It's not, fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- RetVal = FALSE;
- }
- else
- {
- /* Otherwise, decrement lock count, unless we're already at 0*/
- if (!HandleEntry->LockCount--)
- {
- /* In which case we simply lock it back and fail */
- HandleEntry->LockCount++;
- SetLastError(ERROR_NOT_LOCKED);
- RetVal = FALSE;
- }
- else if (!HandleEntry->LockCount)
- {
- /* Nothing to unlock */
- SetLastError(NO_ERROR);
- RetVal = FALSE;
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- RetVal = FALSE;
- }
- _SEH2_END;
-
- /* All done. Unlock the heap and return the pointer */
- RtlUnlockHeap(BaseHeap);
- return RetVal;
-}
-
-/*
- * @implemented
- */
-BOOL
-NTAPI
-GlobalUnWire(HGLOBAL hMem)
-{
- /* This is simply an unlock */
- return GlobalUnlock(hMem);
-}
-
-/*
- * @implemented
- */
-LPVOID
-NTAPI
-GlobalWire(HGLOBAL hMem)
-{
- /* This is just a lock */
- return GlobalLock(hMem);
-}
-
-/*
- * @implemented
- */
-BOOL
-NTAPI
-GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
-{
- SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
- VM_COUNTERS VmCounters;
- QUOTA_LIMITS QuotaLimits;
- ULONGLONG PageFile, PhysicalMemory;
-
- if (lpBuffer->dwLength != sizeof(*lpBuffer))
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* Query performance information */
- NtQuerySystemInformation(SystemPerformanceInformation,
- &PerformanceInfo,
- sizeof(PerformanceInfo),
- NULL);
-
- /* Calculate memory load */
- lpBuffer->dwMemoryLoad = ((DWORD)(BaseStaticServerData->SysInfo.NumberOfPhysicalPages -
- PerformanceInfo.AvailablePages) * 100) /
- BaseStaticServerData->SysInfo.NumberOfPhysicalPages;
-
- /* Save physical memory */
- PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages *
- BaseStaticServerData->SysInfo.PageSize;
- lpBuffer->ullTotalPhys = PhysicalMemory;
-
- /* Now save available physical memory */
- PhysicalMemory = PerformanceInfo.AvailablePages *
- BaseStaticServerData->SysInfo.PageSize;
- lpBuffer->ullAvailPhys = PhysicalMemory;
-
- /* Query VM and Quota Limits */
- NtQueryInformationProcess(NtCurrentProcess(),
- ProcessQuotaLimits,
- &QuotaLimits,
- sizeof(QUOTA_LIMITS),
- NULL);
- NtQueryInformationProcess(NtCurrentProcess(),
- ProcessVmCounters,
- &VmCounters,
- sizeof(VM_COUNTERS),
- NULL);
-
- /* Save the commit limit */
- lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
- PerformanceInfo.CommitLimit);
- lpBuffer->ullTotalPageFile *= BaseStaticServerData->SysInfo.PageSize;
-
- /* Calculate how many pages are left */
- PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
-
- /* Save the total */
- lpBuffer->ullAvailPageFile = min(PageFile,
- QuotaLimits.PagefileLimit -
- VmCounters.PagefileUsage);
- lpBuffer->ullAvailPageFile *= BaseStaticServerData->SysInfo.PageSize;
-
- /* Now calculate the total virtual space */
- lpBuffer->ullTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress -
- BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1;
-
- /* And finally the available virtual space */
- lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual - VmCounters.VirtualSize;
- lpBuffer->ullAvailExtendedVirtual = 0;
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
-{
- MEMORYSTATUSEX lpBufferEx;
-
- /* Call the extended function */
- lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
- if (GlobalMemoryStatusEx(&lpBufferEx))
- {
- /* Reset the right size and fill out the information */
- lpBuffer->dwLength = sizeof(MEMORYSTATUS);
- lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
- lpBuffer->dwTotalPhys = (SIZE_T)min(lpBufferEx.ullTotalPhys, MAXULONG_PTR);
- lpBuffer->dwAvailPhys = (SIZE_T)min(lpBufferEx.ullAvailPhys, MAXULONG_PTR);
- lpBuffer->dwTotalPageFile = (SIZE_T)min(lpBufferEx.ullTotalPageFile, MAXULONG_PTR);
- lpBuffer->dwAvailPageFile = (SIZE_T)min(lpBufferEx.ullAvailPageFile, MAXULONG_PTR);
- lpBuffer->dwTotalVirtual = (SIZE_T)min(lpBufferEx.ullTotalVirtual, MAXULONG_PTR);
- lpBuffer->dwAvailVirtual = (SIZE_T)min(lpBufferEx.ullAvailVirtual, MAXULONG_PTR);
- }
-}
-
-/*
- * @implemented
- */
-HLOCAL
-NTAPI
-LocalAlloc(UINT uFlags,
- SIZE_T dwBytes)
-{
- ULONG Flags = 0;
- PVOID Ptr = NULL;
- HANDLE hMemory;
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- BASE_TRACE_ALLOC(dwBytes, uFlags);
- ASSERT(BaseHeap);
-
- /* Make sure the flags are valid */
- if (uFlags & ~LMEM_VALID_FLAGS)
- {
- /* They aren't, fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
- }
-
- /* Convert ZEROINIT */
- if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
-
- /* Check if we're not movable, which means pointer-based heap */
- if (!(uFlags & LMEM_MOVEABLE))
- {
- /* Allocate heap for it */
- Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
- BASE_TRACE_ALLOC2(Ptr);
- return Ptr;
- }
-
- /* This is heap based, so lock it in first */
- RtlLockHeap(BaseHeap);
-
- /*
- * Disable locking, enable custom flags, and write the
- * movable flag (deprecated)
- */
- Flags |= HEAP_NO_SERIALIZE |
- HEAP_SETTABLE_USER_VALUE |
- BASE_HEAP_FLAG_MOVABLE;
-
- /* Allocate the handle */
- HandleEntry = BaseHeapAllocEntry();
- if (!HandleEntry)
- {
- /* Fail */
- hMemory = NULL;
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- BASE_TRACE_FAILURE();
- goto Quickie;
- }
-
- /* Get the object and make sure we have size */
- hMemory = &HandleEntry->Object;
- if (dwBytes)
- {
- /* Allocate the actual memory for it */
- Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
- BASE_TRACE_PTR(HandleEntry, Ptr);
- if (!Ptr)
- {
- /* We failed, manually set the allocate flag and free the handle */
- HandleEntry->Flags = RTL_HANDLE_VALID;
- BaseHeapFreeEntry(HandleEntry);
-
- /* For the cleanup case */
- HandleEntry = NULL;
- }
- else
- {
- /* All worked well, save our heap entry */
- RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
- }
- }
-
-Quickie:
- /* Cleanup! First unlock the heap */
- RtlUnlockHeap(BaseHeap);
-
- /* Check if a handle was allocated */
- if (HandleEntry)
- {
- /* Set the pointer and allocated flag */
- HandleEntry->Object = Ptr;
- HandleEntry->Flags = RTL_HANDLE_VALID;
- if (!Ptr)
- {
- /* We don't have a valid pointer, but so reuse this handle */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
- }
-
- /* Check if the handle is discardable */
- if (uFlags & GMEM_DISCARDABLE)
- {
- /* Save it in the handle entry */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
-
- /* Check if the handle is moveable */
- if (uFlags & GMEM_MOVEABLE)
- {
- /* Save it in the handle entry */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
- }
-
- /* Set the pointer */
- Ptr = hMemory;
- }
-
- /* Return the pointer */
- return Ptr;
-}
-
-/*
- * @implemented
- */
-SIZE_T
-NTAPI
-LocalCompact(UINT dwMinFree)
-{
- /* Call the RTL Heap Manager */
- return RtlCompactHeap(BaseHeap, 0);
-}
-
-/*
- * @implemented
- */
-UINT
-NTAPI
-LocalFlags(HLOCAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- HANDLE Handle = NULL;
- ULONG Flags = 0;
- UINT uFlags = LMEM_INVALID_HANDLE;
-
- /* Start by locking the heap */
- RtlLockHeap(BaseHeap);
-
- /* Check if this is a simple RTL Heap Managed block */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Then we'll query RTL Heap */
- RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
- BASE_TRACE_PTR(Handle, hMem);
-
- /*
- * Check if RTL Heap didn't find a handle associated with us or
- * said that this heap isn't movable, which means something we're
- * really not a handle-based heap.
- */
- if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
- {
- /* Then set the flags to 0 */
- uFlags = 0;
- }
- else
- {
- /* Otherwise we're handle-based, so get the internal handle */
- hMem = Handle;
- }
- }
-
- /* Check if the handle is actually an entry in our table */
- if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
- {
- /* Then get the entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure it's a valid handle */
- if (BaseHeapValidateEntry(HandleEntry))
- {
- /* Get the lock count first */
- uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT;
-
- /* Now check if it's discardable */
- if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
- {
- /* Set the Win32 Flag */
- uFlags |= LMEM_DISCARDABLE;
- }
-
- /* Now check if it's discarded */
- if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
- /* Set the Win32 Flag */
- uFlags |= LMEM_DISCARDED;
- }
- }
-
- /* Check if by now, we still haven't gotten any useful flags */
- if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
-
- /* All done! Unlock heap and return Win32 Flags */
- RtlUnlockHeap(BaseHeap);
- return uFlags;
-}
-
-/*
- * @implemented
- */
-HLOCAL
-NTAPI
-LocalFree(HLOCAL hMem)
-{
- /* This is identical to a Global Free */
- return GlobalFree(hMem);
-}
-
-/*
- * @implemented
- */
-HLOCAL
-NTAPI
-LocalHandle(LPCVOID pMem)
-{
- /* This is identical to a Global Handle */
- return GlobalHandle(pMem);
-}
-
-/*
- * @implemented
- */
-LPVOID
-NTAPI
-LocalLock(HLOCAL hMem)
-{
- /* This is the same as a GlobalLock, assuming these never change */
- C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT);
- return GlobalLock(hMem);
-}
-
-HLOCAL
-NTAPI
-LocalReAlloc(HLOCAL hMem,
- SIZE_T dwBytes,
- UINT uFlags)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- LPVOID Ptr;
- ULONG Flags = 0;
-
- /* Convert ZEROINIT */
- if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
-
- /* If this wasn't a movable heap, then we MUST re-alloc in place */
- if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
-
- /* Lock the heap and disable built-in locking in the RTL Heap functions */
- RtlLockHeap(BaseHeap);
- Flags |= HEAP_NO_SERIALIZE;
-
- /* Check if this is a simple handle-based block */
- if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Get the entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
-
- /* Make sure the handle is valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* Fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- hMem = NULL;
- }
- else if (uFlags & LMEM_MODIFY)
- {
- /* User is changing flags... check if the memory was discardable */
- if (uFlags & LMEM_DISCARDABLE)
- {
- /* Then set the flag */
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
- else
- {
- /* Otherwise, remove the flag */
- HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE;
- }
- }
- else
- {
- /* Otherwise, get the object and check if we have no size */
- Ptr = HandleEntry->Object;
- if (!dwBytes)
- {
- /* Clear the handle and check for a pointer */
- hMem = NULL;
- if (Ptr)
- {
- /* Make sure the handle isn't locked */
- if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount))
- {
- /* Free the current heap */
- RtlFreeHeap(BaseHeap, Flags, Ptr);
-
- /* Free the handle */
- HandleEntry->Object = NULL;
- HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
-
- /* Get the object pointer */
- hMem = &HandleEntry->Object;
- }
- }
- else
- {
- /* Otherwise just return the object pointer */
- hMem = &HandleEntry->Object;
- }
- }
- else
- {
- /* Otherwise, we're allocating, so set the new flags needed */
- Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
- if (!Ptr)
- {
- /* We don't have a base, so allocate one */
- Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
- BASE_TRACE_ALLOC2(Ptr);
- if (Ptr)
- {
- /* Allocation succeeded, so save our entry */
- RtlSetUserValueHeap(BaseHeap,
- HEAP_NO_SERIALIZE,
- Ptr,
- hMem);
- }
- }
- else
- {
- /*
- * If it's not movable or currently locked, we MUST allocate
- * in-place!
- */
- if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount))
- {
- /* Set the flag */
- Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
- }
- else
- {
- /* Otherwise clear the flag if we set it previously */
- Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
- }
-
- /* And do the re-allocation */
- Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
- }
-
- /* Make sure we have a pointer by now */
- if (Ptr)
- {
- /* Write it in the handle entry and mark it in use */
- HandleEntry->Object = Ptr;
- HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
- }
- else
- {
- /* Otherwise we failed */
- hMem = NULL;
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- }
- }
- }
- }
- else if (!(uFlags & LMEM_MODIFY))
- {
- /* Otherwise, this is a simple RTL Managed Heap, so just call it */
- hMem = RtlReAllocateHeap(BaseHeap,
- Flags | HEAP_NO_SERIALIZE,
- hMem,
- dwBytes);
- if (!hMem)
- {
- /* Fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- }
- }
-
- /* All done, unlock the heap and return the pointer */
- RtlUnlockHeap(BaseHeap);
- return hMem;
-}
-
-/*
- * @implemented
- */
-SIZE_T
-WINAPI
-LocalShrink(HLOCAL hMem,
- UINT cbNewSize)
-{
- /* Call RTL */
- return RtlCompactHeap(BaseHeap, 0);
-}
-
-/*
- * @implemented
- */
-SIZE_T
-NTAPI
-LocalSize(HLOCAL hMem)
-{
- /* This is the same as a Global Size */
- return GlobalSize(hMem);
-}
-
-/*
- * @implemented
- */
-BOOL
-NTAPI
-LocalUnlock(HLOCAL hMem)
-{
- PBASE_HEAP_HANDLE_ENTRY HandleEntry;
- BOOL RetVal = TRUE;
-
- /* Check if this was a simple allocated heap entry */
- if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
- {
- /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */
- SetLastError(ERROR_NOT_LOCKED);
- return FALSE;
- }
-
- /* Otherwise, lock the heap */
- RtlLockHeap(BaseHeap);
-
- /* Get the handle entry */
- HandleEntry = BaseHeapGetEntry(hMem);
- BASE_TRACE_HANDLE(HandleEntry, hMem);
- _SEH2_TRY
- {
- /* Make sure it's valid */
- if (!BaseHeapValidateEntry(HandleEntry))
- {
- /* It's not, fail */
- BASE_TRACE_FAILURE();
- SetLastError(ERROR_INVALID_HANDLE);
- RetVal = FALSE;
- }
- else
- {
- /* Otherwise, decrement lock count, unless we're already at 0*/
- if (!HandleEntry->LockCount--)
- {
- /* In which case we simply lock it back and fail */
- HandleEntry->LockCount++;
- SetLastError(ERROR_NOT_LOCKED);
- RetVal = FALSE;
- }
- else if (!HandleEntry->LockCount)
- {
- /* Nothing to unlock */
- SetLastError(NO_ERROR);
- RetVal = FALSE;
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- RetVal = FALSE;
- }
- _SEH2_END;
-
- /* All done. Unlock the heap and return the pointer */
- RtlUnlockHeap(BaseHeap);
- return RetVal;
-}
-
-/* EOF */