/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    lmem.c

Abstract:

    This module contains the Win32 Local Memory Management APIs

Author:

    Steve Wood (stevewo) 24-Sep-1990

Revision History:

--*/

#include "basedll.h"

void
BaseDllInitializeMemoryManager( VOID )
{
    BaseHeap = RtlProcessHeap();
    RtlInitializeHandleTable( 0xFFFF,
                              sizeof( BASE_HANDLE_TABLE_ENTRY ),
                              &BaseHeapHandleTable
                            );
    NtQuerySystemInformation(SystemRangeStartInformation,
                             &SystemRangeStart,
                             sizeof(SystemRangeStart),
                             NULL);
}

#if i386
#pragma optimize("y",off)
#endif

HLOCAL
WINAPI
LocalAlloc(
    UINT uFlags,
    SIZE_T uBytes
    )
{
    PBASE_HANDLE_TABLE_ENTRY HandleEntry;
    HANDLE hMem;
    ULONG Flags;
    LPSTR p;

    if (uFlags & ~LMEM_VALID_FLAGS) {
        SetLastError( ERROR_INVALID_PARAMETER );
        return( NULL );
        }

    Flags = 0;
    if (uFlags & LMEM_ZEROINIT) {
        Flags |= HEAP_ZERO_MEMORY;
        }

    if (!(uFlags & LMEM_MOVEABLE)) {
        p = RtlAllocateHeap( BaseHeap,
                             MAKE_TAG( LMEM_TAG ) | Flags,
                             uBytes
                           );
        if (p == NULL) {
            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
            }

        return( p );
        }

    RtlLockHeap( BaseHeap );
    Flags |= HEAP_NO_SERIALIZE | HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVEABLE;
    try {
        p = NULL;
        HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)RtlAllocateHandle( &BaseHeapHandleTable, NULL );
        if (HandleEntry == NULL) {
            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
            goto Fail;
            }

        hMem = (HANDLE)&HandleEntry->Object;
        if (uBytes != 0) {
            p = (LPSTR)RtlAllocateHeap( BaseHeap, MAKE_TAG( LMEM_TAG ) | Flags, uBytes );
            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 );
                }
            }
        else {
            p = NULL;
            }
Fail:   ;
        }
    except (EXCEPTION_EXECUTE_HANDLER) {
        p = NULL;
        BaseSetLastNTError( GetExceptionCode() );
        }

    RtlUnlockHeap( BaseHeap );

    if (HandleEntry != NULL) {
        if (HandleEntry->Object = p) {
            HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
            }
        else {
            HandleEntry->Flags = RTL_HANDLE_ALLOCATED | BASE_HANDLE_DISCARDED;
            }

        if (uFlags & LMEM_DISCARDABLE) {
            HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
            }

        if (uFlags & LMEM_MOVEABLE) {
            HandleEntry->Flags |= BASE_HANDLE_MOVEABLE;
            }

        p = (LPSTR)hMem;
        }

    return( (HANDLE)p );
}


HLOCAL
WINAPI
LocalReAlloc(
    HLOCAL hMem,
    SIZE_T uBytes,
    UINT uFlags
    )
{
    PBASE_HANDLE_TABLE_ENTRY HandleEntry;
    LPSTR p;
    ULONG Flags;

    if ((uFlags & ~(LMEM_VALID_FLAGS | LMEM_MODIFY)) ||
        ((uFlags & LMEM_DISCARDABLE) && !(uFlags & LMEM_MODIFY))
       ) {
#if DBG
        DbgPrint( "*** LocalReAlloc( %lx ) - invalid flags\n", uFlags );
        BaseHeapBreakPoint();
#endif
        SetLastError( ERROR_INVALID_PARAMETER );
        return( NULL );
        }

    Flags = 0;
    if (uFlags & LMEM_ZEROINIT) {
        Flags |= HEAP_ZERO_MEMORY;
        }
    if (!(uFlags & LMEM_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( "*** LocalReAlloc( %lx ) - invalid handle\n", hMem );
                BaseHeapBreakPoint();
#endif
                SetLastError( ERROR_INVALID_HANDLE );
                hMem = NULL;
                }
            else
            if (uFlags & LMEM_MODIFY) {
                if (uFlags & LMEM_DISCARDABLE) {
                    HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
                    }
                else {
                    HandleEntry->Flags &= ~BASE_HANDLE_DISCARDABLE;
                    }
                }
            else {
                p = HandleEntry->Object;
                if (uBytes == 0) {
                    hMem = NULL;
                    if (p != NULL) {
                        if ((uFlags & LMEM_MOVEABLE) && HandleEntry->LockCount == 0) {
                            if (RtlFreeHeap( BaseHeap, Flags | HEAP_NO_SERIALIZE, p )) {
                                HandleEntry->Object = NULL;
                                HandleEntry->Flags |= BASE_HANDLE_DISCARDED;
                                hMem = (HANDLE)&HandleEntry->Object;
                                }
                            }
                        else {
#if DBG
                            DbgPrint( "*** LocalReAlloc( %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( LMEM_TAG ) | Flags, uBytes );
                        if (p != NULL) {
                            RtlSetUserValueHeap( BaseHeap, HEAP_NO_SERIALIZE, p, hMem );
                            }
                        }
                    else {
                        if (!(uFlags & LMEM_MOVEABLE) &&
                            HandleEntry->LockCount != 0
                           ) {
                            Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
                            }
                        else {
                            Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
                            }

                        p = RtlReAllocateHeap( BaseHeap, MAKE_TAG( LMEM_TAG ) | Flags, p, uBytes );
                        }

                    if (p != NULL) {
                        HandleEntry->Object = p;
                        HandleEntry->Flags &= ~BASE_HANDLE_DISCARDED;
                        }
                    else {
                        hMem = NULL;
                        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                        }
                    }
                }
            }
        else
        if (!(uFlags & LMEM_MODIFY)) {
            hMem = RtlReAllocateHeap( BaseHeap, MAKE_TAG( LMEM_TAG ) | Flags, (PVOID)hMem, uBytes );
            if (hMem == NULL) {
                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
                }
            }
        }
    except (EXCEPTION_EXECUTE_HANDLER) {
        hMem = NULL;
        BaseSetLastNTError( GetExceptionCode() );
        }

    RtlUnlockHeap( BaseHeap );

    return( (LPSTR)hMem );
}

PVOID
WINAPI
LocalLock(
    HLOCAL 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( "*** LocalLock( %lx ) - invalid handle\n", hMem );
                BaseHeapBreakPoint();
#endif
                SetLastError( ERROR_INVALID_HANDLE );
                p = NULL;
                }
            else {
                p = HandleEntry->Object;
                if (p != NULL) {
                    if (HandleEntry->LockCount++ == LMEM_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 ) {
            return NULL;
            }
        return( (LPSTR)hMem );
        }
}

HLOCAL
WINAPI
LocalHandle(
    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
LocalUnlock(
    HLOCAL hMem
    )
{
    PBASE_HANDLE_TABLE_ENTRY HandleEntry;
    BOOL Result;

    Result = FALSE;
    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( "*** LocalUnlock( %lx ) - invalid handle\n", hMem );
                BaseHeapBreakPoint();
#endif
                SetLastError( ERROR_INVALID_HANDLE );
                }
            else
            if (HandleEntry->LockCount-- == 0) {
                HandleEntry->LockCount++;
                SetLastError( ERROR_NOT_LOCKED );
                }
            else
            if (HandleEntry->LockCount != 0) {
                Result = TRUE;
                }
            else {
                SetLastError( NO_ERROR );
                }
            }
        except (EXCEPTION_EXECUTE_HANDLER) {
            BaseSetLastNTError( GetExceptionCode() );
            }

        RtlUnlockHeap( BaseHeap );
        }
    else {
        SetLastError( ERROR_NOT_LOCKED );
        }

    return( Result );
}


SIZE_T
WINAPI
LocalSize(
    HLOCAL hMem
    )
{
    PBASE_HANDLE_TABLE_ENTRY HandleEntry;
    PVOID Handle;
    ULONG Flags;
    SIZE_T uSize;

    uSize = 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)) {
                uSize = 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( "*** LocalSize( %lx ) - invalid handle\n", hMem );
                BaseHeapBreakPoint();
#endif
                SetLastError( ERROR_INVALID_HANDLE );
                }
            else
            if (HandleEntry->Flags & BASE_HANDLE_DISCARDED) {
                uSize = HandleEntry->Size;
                }
            else {
                uSize = RtlSizeHeap( BaseHeap, HEAP_NO_SERIALIZE, HandleEntry->Object );
                }
            }
        }
    except (EXCEPTION_EXECUTE_HANDLER) {
        BaseSetLastNTError( GetExceptionCode() );
        }

    RtlUnlockHeap( BaseHeap );

    if (uSize == MAXULONG_PTR) {
        SetLastError( ERROR_INVALID_HANDLE );
        return 0;
        }
    else {
        return uSize;
        }
}


UINT
WINAPI
LocalFlags(
    HLOCAL hMem
    )
{
    PBASE_HANDLE_TABLE_ENTRY HandleEntry;
    HANDLE Handle;
    ULONG Flags;
    UINT uFlags;

    uFlags = LMEM_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 & LMEM_LOCKCOUNT;
                if (HandleEntry->Flags & BASE_HANDLE_DISCARDED) {
                    uFlags |= LMEM_DISCARDED;
                    }

                if (HandleEntry->Flags & BASE_HANDLE_DISCARDABLE) {
                    uFlags |= LMEM_DISCARDABLE;
                    }
                }
            }

        if (uFlags == LMEM_INVALID_HANDLE) {
#if DBG
            DbgPrint( "*** LocalFlags( %lx ) - invalid handle\n", hMem );
            BaseHeapBreakPoint();
#endif
            SetLastError( ERROR_INVALID_HANDLE );
            }
        }
    except (EXCEPTION_EXECUTE_HANDLER) {
        BaseSetLastNTError( GetExceptionCode() );
        }

    RtlUnlockHeap( BaseHeap );

    return( uFlags );
}


HLOCAL
WINAPI
LocalFree(
    HLOCAL hMem
    )
{
    PBASE_HANDLE_TABLE_ENTRY HandleEntry;
    LPSTR p;

    try {
        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( "*** LocalFree( %lx ) - invalid handle\n", hMem );
                BaseHeapBreakPoint();
#endif
                SetLastError( ERROR_INVALID_HANDLE );
                p = NULL;
                }
            else {
#if DBG
                if (HandleEntry->LockCount != 0) {
                    DbgPrint( "BASE: LocalFree 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
LocalCompact(
    UINT uMinFree
    )
{
    return RtlCompactHeap( BaseHeap, 0 );
}

SIZE_T
WINAPI
LocalShrink(
    HLOCAL hMem,
    UINT cbNewSize
    )
{
    return RtlCompactHeap( BaseHeap, 0 );
}


HANDLE
WINAPI
HeapCreate(
    DWORD flOptions,
    SIZE_T dwInitialSize,
    SIZE_T dwMaximumSize
    )
{
    HANDLE hHeap;
    ULONG GrowthThreshold;
    ULONG Flags;


    Flags = (flOptions & (HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE)) | HEAP_CLASS_1;
    GrowthThreshold = 0;

    if (dwMaximumSize < BASE_SYSINFO.PageSize) {

        if (dwMaximumSize == 0) {

            GrowthThreshold = BASE_SYSINFO.PageSize * 16;
            Flags |= HEAP_GROWABLE;
            }
        else {
            dwMaximumSize = BASE_SYSINFO.PageSize;
            }
        }

    if (GrowthThreshold == 0 && dwInitialSize > dwMaximumSize) {
        dwMaximumSize = dwInitialSize;
        }

    hHeap = (HANDLE)RtlCreateHeap( Flags,
                                   NULL,
                                   dwMaximumSize,
                                   dwInitialSize,
                                   0,
                                   NULL
                                 );
    if (hHeap == NULL) {
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
        }

    return( hHeap );
}

BOOL
WINAPI
HeapDestroy(
    HANDLE hHeap
    )
{
    if (RtlDestroyHeap( (PVOID)hHeap ) == NULL ) {
        return( TRUE );
        }
    else {
        SetLastError( ERROR_INVALID_HANDLE );
        return( FALSE );
        }
}

BOOL
WINAPI
HeapExtend(
    HANDLE hHeap,
    DWORD dwFlags,
    LPVOID lpBase,
    DWORD dwBytes
    )
{
    NTSTATUS Status;

    Status = RtlExtendHeap( hHeap, dwFlags, lpBase, dwBytes );
    if (NT_SUCCESS( Status )) {
        return TRUE;
        }
    else {
        BaseSetLastNTError( Status );
        }
    return FALSE;
}

WINBASEAPI
DWORD
WINAPI
HeapCreateTagsW(
    HANDLE hHeap,
    DWORD dwFlags,
    LPCWSTR lpTagPrefix,
    LPCWSTR lpTagNames
    )
{
    return RtlCreateTagHeap( hHeap, dwFlags, (PWSTR)lpTagPrefix, (PWSTR)lpTagNames );
}

WINBASEAPI
LPCWSTR
WINAPI
HeapQueryTagW(
    HANDLE hHeap,
    DWORD dwFlags,
    WORD wTagIndex,
    BOOL bResetCounters,
    LPHEAP_TAG_INFO TagInfo
    )
{
    ASSERT( sizeof(RTL_HEAP_TAG_INFO) == sizeof(HEAP_TAG_INFO) );
    return RtlQueryTagHeap( hHeap,
                            dwFlags,
                            wTagIndex,
                            (BOOLEAN)bResetCounters,
                            (PRTL_HEAP_TAG_INFO)TagInfo
                          );
}


BOOL
WINAPI
HeapSummary(
    HANDLE hHeap,
    DWORD dwFlags,
    LPHEAP_SUMMARY lpSummary
    )
{
    NTSTATUS Status;
    RTL_HEAP_USAGE HeapInfo;

    if (lpSummary->cb != sizeof( *lpSummary )) {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
        }

    HeapInfo.Length = sizeof( HeapInfo );
    Status = RtlUsageHeap( hHeap,
                           dwFlags & ~(HEAP_USAGE_ALLOCATED_BLOCKS |
                                       HEAP_USAGE_FREE_BUFFER
                                      ),
                           &HeapInfo
                         );
    if (NT_SUCCESS( Status )) {
        lpSummary->cbAllocated = HeapInfo.BytesAllocated;
        lpSummary->cbCommitted = HeapInfo.BytesCommitted;
        return TRUE;
        }
    else {
        BaseSetLastNTError( Status );
        return FALSE;
        }
}

BOOL
WINAPI
HeapUsage(
    HANDLE hHeap,
    DWORD dwFlags,
    BOOL bFirstCall,
    BOOL bLastCall,
    PHEAP_USAGE lpUsage
    )
{
    NTSTATUS Status;

    if (lpUsage->cb != sizeof( *lpUsage ) || (bFirstCall & bLastCall)) {
        SetLastError( ERROR_INVALID_PARAMETER );
        return FALSE;
        }

    dwFlags &= ~(HEAP_USAGE_ALLOCATED_BLOCKS |
                 HEAP_USAGE_FREE_BUFFER
                );

    if (bLastCall) {
        dwFlags |= HEAP_USAGE_FREE_BUFFER;
        }
    else {
        dwFlags |= HEAP_USAGE_ALLOCATED_BLOCKS;
        if (bFirstCall) {
            RtlZeroMemory( (&lpUsage->cb)+1, sizeof( *lpUsage ) - sizeof( lpUsage->cb ) );
            }
        }

    ASSERT( sizeof(RTL_HEAP_USAGE) == sizeof(HEAP_USAGE) );
    Status = RtlUsageHeap( hHeap, dwFlags, (PRTL_HEAP_USAGE)lpUsage );
    if (NT_SUCCESS( Status )) {
        if (Status == STATUS_MORE_ENTRIES) {
            return TRUE;
            }
        else {
            SetLastError( NO_ERROR );
            return FALSE;
            }
        }
    else {
        BaseSetLastNTError( Status );
        return FALSE;
        }
}

BOOL
WINAPI
HeapValidate(
    HANDLE hHeap,
    DWORD dwFlags,
    LPVOID lpMem
    )
{
    return RtlValidateHeap( hHeap, dwFlags, lpMem );
}

HANDLE
WINAPI
GetProcessHeap( VOID )
{
    return RtlProcessHeap();
}


WINBASEAPI
DWORD
WINAPI
GetProcessHeaps(
    DWORD NumberOfHeaps,
    PHANDLE ProcessHeaps
    )
{
    return RtlGetProcessHeaps( NumberOfHeaps, ProcessHeaps );
}


WINBASEAPI
SIZE_T
WINAPI
HeapCompact(
    HANDLE hHeap,
    DWORD dwFlags
    )
{
    return RtlCompactHeap( hHeap, dwFlags );
}


WINBASEAPI
BOOL
WINAPI
HeapLock(
    HANDLE hHeap
    )
{
    return RtlLockHeap( hHeap );
}


WINBASEAPI
BOOL
WINAPI
HeapUnlock(
    HANDLE hHeap
    )
{
    return RtlUnlockHeap( hHeap );
}

WINBASEAPI
BOOL
WINAPI
HeapWalk(
    HANDLE hHeap,
    LPPROCESS_HEAP_ENTRY lpEntry
    )
{
    RTL_HEAP_WALK_ENTRY Entry;
    NTSTATUS Status;

    if (lpEntry->lpData == NULL) {
        Entry.DataAddress = NULL;
        Status = RtlWalkHeap( hHeap, &Entry );
        }
    else {
        Entry.DataAddress = lpEntry->lpData;
        Entry.SegmentIndex = lpEntry->iRegionIndex;
        if (lpEntry->wFlags & PROCESS_HEAP_REGION) {
            Entry.Flags = RTL_HEAP_SEGMENT;
            }
        else
        if (lpEntry->wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) {
            Entry.Flags = RTL_HEAP_UNCOMMITTED_RANGE;
            Entry.DataSize = lpEntry->cbData;
            }
        else
        if (lpEntry->wFlags & PROCESS_HEAP_ENTRY_BUSY) {
            Entry.Flags = RTL_HEAP_BUSY;
            }
        else {
            Entry.Flags = 0;
            }

        Status = RtlWalkHeap( hHeap, &Entry );
        }

    if (NT_SUCCESS( Status )) {
        lpEntry->lpData = Entry.DataAddress;
        lpEntry->cbData = (DWORD)Entry.DataSize;
        lpEntry->cbOverhead = Entry.OverheadBytes;
        lpEntry->iRegionIndex = Entry.SegmentIndex;
        if (Entry.Flags & RTL_HEAP_BUSY) {
            lpEntry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
            if (Entry.Flags & BASE_HEAP_FLAG_DDESHARE) {
                lpEntry->wFlags |= PROCESS_HEAP_ENTRY_DDESHARE;
                }

            if (Entry.Flags & BASE_HEAP_FLAG_MOVEABLE) {
                lpEntry->wFlags |= PROCESS_HEAP_ENTRY_MOVEABLE;
                lpEntry->Block.hMem = (HLOCAL)Entry.Block.Settable;
                }

            memset( lpEntry->Block.dwReserved, 0, sizeof( lpEntry->Block.dwReserved ) );
            }
        else
        if (Entry.Flags & RTL_HEAP_SEGMENT) {
            lpEntry->wFlags = PROCESS_HEAP_REGION;
            lpEntry->Region.dwCommittedSize = Entry.Segment.CommittedSize;
            lpEntry->Region.dwUnCommittedSize = Entry.Segment.UnCommittedSize;
            lpEntry->Region.lpFirstBlock = Entry.Segment.FirstEntry;
            lpEntry->Region.lpLastBlock = Entry.Segment.LastEntry;
            }
        else
        if (Entry.Flags & RTL_HEAP_UNCOMMITTED_RANGE) {
            lpEntry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
            memset( &lpEntry->Region, 0, sizeof( lpEntry->Region ) );
            }
        else {
            lpEntry->wFlags = 0;
            }

        return TRUE;
        }
    else {
        BaseSetLastNTError( Status );
        return FALSE;
        }
}

WINBASEAPI
BOOL
WINAPI
HeapSetInformation (
    IN PVOID HeapHandle, 
    IN HEAP_INFORMATION_CLASS HeapInformationClass,
    IN PVOID HeapInformation OPTIONAL,
    IN SIZE_T HeapInformationLength OPTIONAL
    )
{
    NTSTATUS Status;

    Status = RtlSetHeapInformation( HeapHandle, 
                                    HeapInformationClass, 
                                    HeapInformation, 
                                    HeapInformationLength );
    if (NT_SUCCESS( Status )) {
        return TRUE;
        }
    else {
        BaseSetLastNTError( Status );
        }
    return FALSE;
}

WINBASEAPI
BOOL
WINAPI
HeapQueryInformation (
    IN PVOID HeapHandle, 
    IN HEAP_INFORMATION_CLASS HeapInformationClass,
    OUT PVOID HeapInformation OPTIONAL,
    IN SIZE_T HeapInformationLength OPTIONAL,
    OUT PSIZE_T ReturnLength OPTIONAL
    )
{
    NTSTATUS Status;

    Status = RtlQueryHeapInformation( HeapHandle, 
                                      HeapInformationClass, 
                                      HeapInformation, 
                                      HeapInformationLength,
                                      ReturnLength );
    if (NT_SUCCESS( Status )) {
        return TRUE;
        }
    else {
        BaseSetLastNTError( Status );
        }
    return FALSE;
}

#if DBG
VOID
BaseHeapBreakPoint( VOID )
{
    if (NtCurrentPeb()->BeingDebugged)
        {
#if i386
        _asm {  int 3 }
#else
        DbgBreakPoint();
#endif
        }
}
#endif