Moved heap functions to ntdll.
Got rid of internal heap flags.
Reimplemented MapLS to not depend on the segptr heap.

diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec
index da07c78..a8d09c6 100644
--- a/dlls/kernel/kernel32.spec
+++ b/dlls/kernel/kernel32.spec
@@ -500,15 +500,15 @@
 @ stub Heap32ListFirst
 @ stub Heap32ListNext
 @ stub Heap32Next
-@ stdcall HeapAlloc(long long long) HeapAlloc
+@ forward HeapAlloc ntdll.RtlAllocateHeap
 @ stdcall HeapCompact(long long) HeapCompact
 @ stdcall HeapCreate(long long long) HeapCreate
 @ stdcall HeapDestroy(long) HeapDestroy
-@ stdcall HeapFree(long long ptr) HeapFree
+@ forward HeapFree ntdll.RtlFreeHeap
 @ stdcall HeapLock(long) HeapLock
-@ stdcall HeapReAlloc(long long ptr long) HeapReAlloc
+@ forward HeapReAlloc ntdll.RtlReAllocateHeap
 @ stub HeapSetFlags
-@ stdcall HeapSize(long long ptr) HeapSize
+@ forward HeapSize ntdll.RtlSizeHeap
 @ stdcall HeapUnlock(long) HeapUnlock
 @ stdcall HeapValidate(long long ptr) HeapValidate
 @ stdcall HeapWalk(long ptr) HeapWalk
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index f3d214b..5a8a96a 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -11,6 +11,7 @@
 	exception.c \
 	error.c \
 	file.c \
+	heap.c \
 	large_int.c \
 	misc.c \
 	nt.c \
diff --git a/dlls/ntdll/debugtools.c b/dlls/ntdll/debugtools.c
index 8354bef..4c96fe3 100644
--- a/dlls/ntdll/debugtools.c
+++ b/dlls/ntdll/debugtools.c
@@ -14,6 +14,7 @@
 #include "thread.h"
 #include "winbase.h"
 #include "winnt.h"
+#include "ntddk.h"
 #include "wtypes.h"
 
 DECLARE_DEBUG_CHANNEL(tid);
@@ -50,9 +51,9 @@
             tmp.out_pos = tmp.output;
         }
         if (!GetProcessHeap()) return &tmp;
-        /* setup the temp structure in case HeapAlloc wants to print something */
+        /* setup the temp structure in case RtlAllocateHeap wants to print something */
         NtCurrentTeb()->debug_info = &tmp;
-        info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
+        info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) );
         info->str_pos = info->strings;
         info->out_pos = info->output;
         NtCurrentTeb()->debug_info = info;
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
new file mode 100644
index 0000000..ac177e2
--- /dev/null
+++ b/dlls/ntdll/heap.c
@@ -0,0 +1,1424 @@
+/*
+ * Win32 heap functions
+ *
+ * Copyright 1996 Alexandre Julliard
+ * Copyright 1998 Ulrich Weigand
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ntddk.h"
+#include "wine/winbase16.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "heap.h"
+#include "thread.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(heap);
+
+/* Note: the heap data structures are based on what Pietrek describes in his
+ * book 'Windows 95 System Programming Secrets'. The layout is not exactly
+ * the same, but could be easily adapted if it turns out some programs
+ * require it.
+ */
+
+typedef struct tagARENA_INUSE
+{
+    DWORD  size;                    /* Block size; must be the first field */
+    DWORD  magic;                   /* Magic number */
+} ARENA_INUSE;
+
+typedef struct tagARENA_FREE
+{
+    DWORD                 size;     /* Block size; must be the first field */
+    DWORD                 magic;    /* Magic number */
+    struct tagARENA_FREE *next;     /* Next free arena */
+    struct tagARENA_FREE *prev;     /* Prev free arena */
+} ARENA_FREE;
+
+#define ARENA_FLAG_FREE        0x00000001  /* flags OR'ed with arena size */
+#define ARENA_FLAG_PREV_FREE   0x00000002
+#define ARENA_SIZE_MASK        (~3)
+#define ARENA_INUSE_MAGIC      0x44455355      /* Value for arena 'magic' field */
+#define ARENA_FREE_MAGIC       0x45455246      /* Value for arena 'magic' field */
+
+#define ARENA_INUSE_FILLER     0x55
+#define ARENA_FREE_FILLER      0xaa
+
+#define QUIET                  1           /* Suppress messages  */
+#define NOISY                  0           /* Report all errors  */
+
+#define HEAP_NB_FREE_LISTS   4   /* Number of free lists */
+
+/* Max size of the blocks on the free lists */
+static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
+{
+    0x20, 0x80, 0x200, ~0UL
+};
+
+typedef struct
+{
+    DWORD       size;
+    ARENA_FREE  arena;
+} FREE_LIST_ENTRY;
+
+struct tagHEAP;
+
+typedef struct tagSUBHEAP
+{
+    DWORD               size;       /* Size of the whole sub-heap */
+    DWORD               commitSize; /* Committed size of the sub-heap */
+    DWORD               headerSize; /* Size of the heap header */
+    struct tagSUBHEAP  *next;       /* Next sub-heap */
+    struct tagHEAP     *heap;       /* Main heap structure */
+    DWORD               magic;      /* Magic number */
+} SUBHEAP;
+
+#define SUBHEAP_MAGIC    ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
+
+typedef struct tagHEAP
+{
+    SUBHEAP          subheap;       /* First sub-heap */
+    struct tagHEAP  *next;          /* Next heap for this process */
+    CRITICAL_SECTION critSection;   /* Critical section for serialization */
+    FREE_LIST_ENTRY  freeList[HEAP_NB_FREE_LISTS];  /* Free lists */
+    DWORD            flags;         /* Heap flags */
+    DWORD            magic;         /* Magic number */
+} HEAP;
+
+#define HEAP_MAGIC       ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
+
+#define HEAP_DEF_SIZE        0x110000   /* Default heap size = 1Mb + 64Kb */
+#define HEAP_MIN_BLOCK_SIZE  (8+sizeof(ARENA_FREE))  /* Min. heap block size */
+#define COMMIT_MASK          0xffff  /* bitmask for commit/decommit granularity */
+
+static HANDLE processHeap;  /* main process heap */
+
+static HEAP *firstHeap;     /* head of secondary heaps list */
+
+static BOOL HEAP_IsRealArena( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet );
+
+/* SetLastError for ntdll */
+inline static void set_status( NTSTATUS status )
+{
+#if defined(__i386__) && defined(__GNUC__)
+    /* in this case SetLastError is an inline function so we can use it */
+    SetLastError( RtlNtStatusToDosError( status ) );
+#else
+    /* cannot use SetLastError, do it manually */
+    NtCurrentTeb()->last_error = RtlNtStatusToDosError( status );
+#endif
+}
+
+/* set the process main heap */
+static void set_process_heap( HANDLE heap )
+{
+    HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
+    pdb[0x18 / sizeof(HANDLE)] = heap;  /* heap is at offset 0x18 in pdb */
+    processHeap = heap;
+}
+
+
+/***********************************************************************
+ *           HEAP_Dump
+ */
+void HEAP_Dump( HEAP *heap )
+{
+    int i;
+    SUBHEAP *subheap;
+    char *ptr;
+
+    DPRINTF( "Heap: %08lx\n", (DWORD)heap );
+    DPRINTF( "Next: %08lx  Sub-heaps: %08lx",
+	  (DWORD)heap->next, (DWORD)&heap->subheap );
+    subheap = &heap->subheap;
+    while (subheap->next)
+    {
+        DPRINTF( " -> %08lx", (DWORD)subheap->next );
+        subheap = subheap->next;
+    }
+
+    DPRINTF( "\nFree lists:\n Block   Stat   Size    Id\n" );
+    for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
+        DPRINTF( "%08lx free %08lx prev=%08lx next=%08lx\n",
+	      (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
+	      (DWORD)heap->freeList[i].arena.prev,
+	      (DWORD)heap->freeList[i].arena.next );
+
+    subheap = &heap->subheap;
+    while (subheap)
+    {
+        DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
+        DPRINTF( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
+	      (DWORD)subheap, subheap->size, subheap->commitSize );
+	
+        DPRINTF( "\n Block   Stat   Size    Id\n" );
+        ptr = (char*)subheap + subheap->headerSize;
+        while (ptr < (char *)subheap + subheap->size)
+        {
+            if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+            {
+                ARENA_FREE *pArena = (ARENA_FREE *)ptr;
+                DPRINTF( "%08lx free %08lx prev=%08lx next=%08lx\n",
+		      (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
+		      (DWORD)pArena->prev, (DWORD)pArena->next);
+                ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
+                arenaSize += sizeof(ARENA_FREE);
+                freeSize += pArena->size & ARENA_SIZE_MASK;
+            }
+            else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
+            {
+                ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
+                DPRINTF( "%08lx Used %08lx back=%08lx\n",
+                         (DWORD)pArena, pArena->size & ARENA_SIZE_MASK, *((DWORD *)pArena - 1) );
+                ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
+                arenaSize += sizeof(ARENA_INUSE);
+                usedSize += pArena->size & ARENA_SIZE_MASK;
+            }
+            else
+            {
+                ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
+                DPRINTF( "%08lx used %08lx\n",
+		      (DWORD)pArena, pArena->size & ARENA_SIZE_MASK );
+                ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
+                arenaSize += sizeof(ARENA_INUSE);
+                usedSize += pArena->size & ARENA_SIZE_MASK;
+            }
+        }
+        DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
+	      subheap->size, subheap->commitSize, freeSize, usedSize,
+	      arenaSize, (arenaSize * 100) / subheap->size );
+        subheap = subheap->next;
+    }
+}
+
+
+/***********************************************************************
+ *           HEAP_GetPtr
+ * RETURNS
+ *	Pointer to the heap
+ *	NULL: Failure
+ */
+static HEAP *HEAP_GetPtr(
+             HANDLE heap /* [in] Handle to the heap */
+) {
+    HEAP *heapPtr = (HEAP *)heap;
+    if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
+    {
+        ERR("Invalid heap %08x!\n", heap );
+        return NULL;
+    }
+    if (TRACE_ON(heap) && !HEAP_IsRealArena( heapPtr, 0, NULL, NOISY ))
+    {
+        HEAP_Dump( heapPtr );
+        assert( FALSE );
+        return NULL;
+    }
+    return heapPtr;
+}
+
+
+/***********************************************************************
+ *           HEAP_InsertFreeBlock
+ *
+ * Insert a free block into the free list.
+ */
+static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
+{
+    FREE_LIST_ENTRY *pEntry = heap->freeList;
+    while (pEntry->size < pArena->size) pEntry++;
+    pArena->size      |= ARENA_FLAG_FREE;
+    pArena->next       = pEntry->arena.next;
+    pArena->next->prev = pArena;
+    pArena->prev       = &pEntry->arena;
+    pEntry->arena.next = pArena;
+}
+
+
+/***********************************************************************
+ *           HEAP_FindSubHeap
+ * Find the sub-heap containing a given address.
+ *
+ * RETURNS
+ *	Pointer: Success
+ *	NULL: Failure
+ */
+static SUBHEAP *HEAP_FindSubHeap(
+                HEAP *heap, /* [in] Heap pointer */
+                LPCVOID ptr /* [in] Address */
+) {
+    SUBHEAP *sub = &heap->subheap;
+    while (sub)
+    {
+        if (((char *)ptr >= (char *)sub) &&
+            ((char *)ptr < (char *)sub + sub->size)) return sub;
+        sub = sub->next;
+    }
+    return NULL;
+}
+
+
+/***********************************************************************
+ *           HEAP_Commit
+ *
+ * Make sure the heap storage is committed up to (not including) ptr.
+ */
+static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
+{
+    DWORD size = (DWORD)((char *)ptr - (char *)subheap);
+    size = (size + COMMIT_MASK) & ~COMMIT_MASK;
+    if (size > subheap->size) size = subheap->size;
+    if (size <= subheap->commitSize) return TRUE;
+    if (!VirtualAlloc( (char *)subheap + subheap->commitSize,
+                       size - subheap->commitSize, MEM_COMMIT,
+                       PAGE_EXECUTE_READWRITE))
+    {
+        WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n",
+                 size - subheap->commitSize,
+                 (DWORD)((char *)subheap + subheap->commitSize),
+                 (DWORD)subheap->heap );
+        return FALSE;
+    }
+    subheap->commitSize = size;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           HEAP_Decommit
+ *
+ * If possible, decommit the heap storage from (including) 'ptr'.
+ */
+static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
+{
+    DWORD size = (DWORD)((char *)ptr - (char *)subheap);
+    /* round to next block and add one full block */
+    size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1;
+    if (size >= subheap->commitSize) return TRUE;
+    if (!VirtualFree( (char *)subheap + size,
+                      subheap->commitSize - size, MEM_DECOMMIT ))
+    {
+        WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
+                 subheap->commitSize - size,
+                 (DWORD)((char *)subheap + size),
+                 (DWORD)subheap->heap );
+        return FALSE;
+    }
+    subheap->commitSize = size;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           HEAP_CreateFreeBlock
+ *
+ * Create a free block at a specified address. 'size' is the size of the
+ * whole block, including the new arena.
+ */
+static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
+{
+    ARENA_FREE *pFree;
+
+    /* Create a free arena */
+
+    pFree = (ARENA_FREE *)ptr;
+    pFree->magic = ARENA_FREE_MAGIC;
+
+    /* If debugging, erase the freed block content */
+
+    if (TRACE_ON(heap))
+    {
+        char *pEnd = (char *)ptr + size;
+        if (pEnd > (char *)subheap + subheap->commitSize)
+            pEnd = (char *)subheap + subheap->commitSize;
+        if (pEnd > (char *)(pFree + 1))
+            memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
+    }
+
+    /* Check if next block is free also */
+
+    if (((char *)ptr + size < (char *)subheap + subheap->size) &&
+        (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
+    {
+        /* Remove the next arena from the free list */
+        ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
+        pNext->next->prev = pNext->prev;
+        pNext->prev->next = pNext->next;
+        size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
+        if (TRACE_ON(heap))
+            memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
+    }
+
+    /* Set the next block PREV_FREE flag and pointer */
+
+    if ((char *)ptr + size < (char *)subheap + subheap->size)
+    {
+        DWORD *pNext = (DWORD *)((char *)ptr + size);
+        *pNext |= ARENA_FLAG_PREV_FREE;
+        *(ARENA_FREE **)(pNext - 1) = pFree;
+    }
+
+    /* Last, insert the new block into the free list */
+
+    pFree->size = size - sizeof(*pFree);
+    HEAP_InsertFreeBlock( subheap->heap, pFree );
+}
+
+
+/***********************************************************************
+ *           HEAP_MakeInUseBlockFree
+ *
+ * Turn an in-use block into a free block. Can also decommit the end of
+ * the heap, and possibly even free the sub-heap altogether.
+ */
+static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
+{
+    ARENA_FREE *pFree;
+    DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
+
+    /* Check if we can merge with previous block */
+
+    if (pArena->size & ARENA_FLAG_PREV_FREE)
+    {
+        pFree = *((ARENA_FREE **)pArena - 1);
+        size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
+        /* Remove it from the free list */
+        pFree->next->prev = pFree->prev;
+        pFree->prev->next = pFree->next;
+    }
+    else pFree = (ARENA_FREE *)pArena;
+
+    /* Create a free block */
+
+    HEAP_CreateFreeBlock( subheap, pFree, size );
+    size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
+    if ((char *)pFree + size < (char *)subheap + subheap->size)
+        return;  /* Not the last block, so nothing more to do */
+
+    /* Free the whole sub-heap if it's empty and not the original one */
+
+    if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
+        (subheap != &subheap->heap->subheap))
+    {
+        SUBHEAP *pPrev = &subheap->heap->subheap;
+        /* Remove the free block from the list */
+        pFree->next->prev = pFree->prev;
+        pFree->prev->next = pFree->next;
+        /* Remove the subheap from the list */
+        while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
+        if (pPrev) pPrev->next = subheap->next;
+        /* Free the memory */
+        subheap->magic = 0;
+        VirtualFree( subheap, 0, MEM_RELEASE );
+        return;
+    }
+
+    /* Decommit the end of the heap */
+
+    if (!(subheap->heap->flags & HEAP_SHARED)) HEAP_Decommit( subheap, pFree + 1 );
+}
+
+
+/***********************************************************************
+ *           HEAP_ShrinkBlock
+ *
+ * Shrink an in-use block.
+ */
+static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
+{
+    if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
+    {
+        HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
+                              (pArena->size & ARENA_SIZE_MASK) - size );
+	/* assign size plus previous arena flags */
+        pArena->size = size | (pArena->size & ~ARENA_SIZE_MASK);
+    }
+    else
+    {
+        /* Turn off PREV_FREE flag in next block */
+        char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
+        if (pNext < (char *)subheap + subheap->size)
+            *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
+    }
+}
+
+/***********************************************************************
+ *           HEAP_InitSubHeap
+ */
+static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
+                                DWORD commitSize, DWORD totalSize )
+{
+    SUBHEAP *subheap = (SUBHEAP *)address;
+    FREE_LIST_ENTRY *pEntry;
+    int i;
+
+    /* Commit memory */
+
+    if (flags & HEAP_SHARED)
+        commitSize = totalSize;  /* always commit everything in a shared heap */
+    if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
+    {
+        WARN("Could not commit %08lx bytes for sub-heap %08lx\n",
+                   commitSize, (DWORD)address );
+        return FALSE;
+    }
+
+    /* Fill the sub-heap structure */
+
+    subheap->heap       = heap;
+    subheap->size       = totalSize;
+    subheap->commitSize = commitSize;
+    subheap->magic      = SUBHEAP_MAGIC;
+
+    if ( subheap != (SUBHEAP *)heap )
+    {
+        /* If this is a secondary subheap, insert it into list */
+
+        subheap->headerSize = sizeof(SUBHEAP);
+        subheap->next       = heap->subheap.next;
+        heap->subheap.next  = subheap;
+    }
+    else
+    {
+        /* If this is a primary subheap, initialize main heap */
+
+        subheap->headerSize = sizeof(HEAP);
+        subheap->next       = NULL;
+        heap->next          = NULL;
+        heap->flags         = flags;
+        heap->magic         = HEAP_MAGIC;
+
+        /* Build the free lists */
+
+        for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
+        {
+            pEntry->size       = HEAP_freeListSizes[i];
+            pEntry->arena.size = 0 | ARENA_FLAG_FREE;
+            pEntry->arena.next = i < HEAP_NB_FREE_LISTS-1 ?
+                                 &heap->freeList[i+1].arena : &heap->freeList[0].arena;
+            pEntry->arena.prev = i ? &heap->freeList[i-1].arena :
+                                  &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
+            pEntry->arena.magic = ARENA_FREE_MAGIC;
+        }
+
+        /* Initialize critical section */
+
+        RtlInitializeCriticalSection( &heap->critSection );
+    }
+
+    /* Create the first free block */
+
+    HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize, 
+                          subheap->size - subheap->headerSize );
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           HEAP_CreateSubHeap
+ *
+ * Create a sub-heap of the given size.
+ * If heap == NULL, creates a main heap.
+ */
+static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, void *base, DWORD flags,
+                                    DWORD commitSize, DWORD totalSize )
+{
+    LPVOID address = base;
+
+    if (!address)
+    {
+        /* round-up sizes on a 64K boundary */
+        totalSize  = (totalSize + 0xffff) & 0xffff0000;
+        commitSize = (commitSize + 0xffff) & 0xffff0000;
+        if (!commitSize) commitSize = 0x10000;
+        if (totalSize < commitSize) totalSize = commitSize;
+
+        /* allocate the memory block */
+        if (!(address = VirtualAlloc( NULL, totalSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
+        {
+            WARN("Could not VirtualAlloc %08lx bytes\n",
+                 totalSize );
+            return NULL;
+        }
+    }
+
+    /* Initialize subheap */
+
+    if (!HEAP_InitSubHeap( heap ? heap : (HEAP *)address,
+                           address, flags, commitSize, totalSize ))
+    {
+        if (!base) VirtualFree( address, 0, MEM_RELEASE );
+        return NULL;
+    }
+
+    return (SUBHEAP *)address;
+}
+
+
+/***********************************************************************
+ *           HEAP_FindFreeBlock
+ *
+ * Find a free block at least as large as the requested size, and make sure
+ * the requested size is committed.
+ */
+static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
+                                       SUBHEAP **ppSubHeap )
+{
+    SUBHEAP *subheap;
+    ARENA_FREE *pArena;
+    FREE_LIST_ENTRY *pEntry = heap->freeList;
+
+    /* Find a suitable free list, and in it find a block large enough */
+
+    while (pEntry->size < size) pEntry++;
+    pArena = pEntry->arena.next;
+    while (pArena != &heap->freeList[0].arena)
+    {
+        DWORD arena_size = (pArena->size & ARENA_SIZE_MASK) +
+                            sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
+        if (arena_size >= size)
+        {
+            subheap = HEAP_FindSubHeap( heap, pArena );
+            if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
+                                               + size + HEAP_MIN_BLOCK_SIZE))
+                return NULL;
+            *ppSubHeap = subheap;
+            return pArena;
+        }
+        pArena = pArena->next;
+    }
+
+    /* If no block was found, attempt to grow the heap */
+
+    if (!(heap->flags & HEAP_GROWABLE))
+    {
+        WARN("Not enough space in heap %08lx for %08lx bytes\n",
+                 (DWORD)heap, size );
+        return NULL;
+    }
+    /* make sure that we have a big enough size *committed* to fit another
+     * last free arena in !
+     * So just one heap struct, one first free arena which will eventually
+     * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
+     * might get assigned all remaining free space in HEAP_ShrinkBlock() */
+    size += sizeof(SUBHEAP) + sizeof(ARENA_INUSE) + HEAP_MIN_BLOCK_SIZE;
+    if (!(subheap = HEAP_CreateSubHeap( heap, NULL, heap->flags, size,
+                                        max( HEAP_DEF_SIZE, size ) )))
+        return NULL;
+
+    TRACE("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
+                (DWORD)subheap, size, (DWORD)heap );
+
+    *ppSubHeap = subheap;
+    return (ARENA_FREE *)(subheap + 1);
+}
+
+
+/***********************************************************************
+ *           HEAP_IsValidArenaPtr
+ *
+ * Check that the pointer is inside the range possible for arenas.
+ */
+static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
+{
+    int i;
+    SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
+    if (!subheap) return FALSE;
+    if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
+    if (subheap != &heap->subheap) return FALSE;
+    for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
+        if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           HEAP_ValidateFreeArena
+ */
+static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
+{
+    char *heapEnd = (char *)subheap + subheap->size;
+
+#if !defined(ALLOW_UNALIGNED_ACCESS)
+    /* Check for unaligned pointers */
+    if ( (long)pArena % sizeof(void *) != 0 )
+    {
+        ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
+             (DWORD)subheap->heap, (DWORD)pArena );
+        return FALSE;
+    }
+#endif
+
+    /* Check magic number */
+    if (pArena->magic != ARENA_FREE_MAGIC)
+    {
+        ERR("Heap %08lx: invalid free arena magic for %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check size flags */
+    if (!(pArena->size & ARENA_FLAG_FREE) ||
+        (pArena->size & ARENA_FLAG_PREV_FREE))
+    {
+        ERR("Heap %08lx: bad flags %lx for free arena %08lx\n",
+                 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
+    }
+    /* Check arena size */
+    if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
+    {
+        ERR("Heap %08lx: bad size %08lx for free arena %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check that next pointer is valid */
+    if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
+    {
+        ERR("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check that next arena is free */
+    if (!(pArena->next->size & ARENA_FLAG_FREE) ||
+        (pArena->next->magic != ARENA_FREE_MAGIC))
+    { 
+        ERR("Heap %08lx: next arena %08lx invalid for %08lx\n", 
+                 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check that prev pointer is valid */
+    if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
+    {
+        ERR("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check that prev arena is free */
+    if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
+        (pArena->prev->magic != ARENA_FREE_MAGIC))
+    { 
+	/* this often means that the prev arena got overwritten
+	 * by a memory write before that prev arena */
+        ERR("Heap %08lx: prev arena %08lx invalid for %08lx\n", 
+                 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check that next block has PREV_FREE flag */
+    if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
+    {
+        if (!(*(DWORD *)((char *)(pArena + 1) +
+            (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
+        {
+            ERR("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
+                     (DWORD)subheap->heap, (DWORD)pArena );
+            return FALSE;
+        }
+        /* Check next block back pointer */
+        if (*((ARENA_FREE **)((char *)(pArena + 1) +
+            (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
+        {
+            ERR("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
+                     (DWORD)subheap->heap, (DWORD)pArena,
+                     *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           HEAP_ValidateInUseArena
+ */
+static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena, BOOL quiet )
+{
+    char *heapEnd = (char *)subheap + subheap->size;
+
+#if !defined(ALLOW_UNALIGNED_ACCESS)
+    /* Check for unaligned pointers */
+    if ( (long)pArena % sizeof(void *) != 0 )
+    {
+        if ( quiet == NOISY )
+        {
+            ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
+                  (DWORD)subheap->heap, (DWORD)pArena );
+            if ( TRACE_ON(heap) )
+                HEAP_Dump( subheap->heap );
+        }
+        else if ( WARN_ON(heap) )
+        {
+            WARN( "Heap %08lx: unaligned arena pointer %08lx\n",
+                  (DWORD)subheap->heap, (DWORD)pArena );
+            if ( TRACE_ON(heap) )
+                HEAP_Dump( subheap->heap );
+        }
+        return FALSE;
+    }
+#endif
+
+    /* Check magic number */
+    if (pArena->magic != ARENA_INUSE_MAGIC)
+    {
+        if (quiet == NOISY) {
+        ERR("Heap %08lx: invalid in-use arena magic for %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena );
+            if (TRACE_ON(heap))
+               HEAP_Dump( subheap->heap );
+        }  else if (WARN_ON(heap)) {
+            WARN("Heap %08lx: invalid in-use arena magic for %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena );
+            if (TRACE_ON(heap))
+               HEAP_Dump( subheap->heap );
+        }
+        return FALSE;
+    }
+    /* Check size flags */
+    if (pArena->size & ARENA_FLAG_FREE) 
+    {
+        ERR("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
+                 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
+    }
+    /* Check arena size */
+    if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
+    {
+        ERR("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
+                 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check next arena PREV_FREE flag */
+    if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
+        (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
+    {
+        ERR("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
+                 (DWORD)subheap->heap, (DWORD)pArena );
+        return FALSE;
+    }
+    /* Check prev free arena */
+    if (pArena->size & ARENA_FLAG_PREV_FREE)
+    {
+        ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
+        /* Check prev pointer */
+        if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
+        {
+            ERR("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
+                    (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
+            return FALSE;
+        }
+        /* Check that prev arena is free */
+        if (!(pPrev->size & ARENA_FLAG_FREE) ||
+            (pPrev->magic != ARENA_FREE_MAGIC))
+        { 
+            ERR("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n", 
+                     (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
+            return FALSE;
+        }
+        /* Check that prev arena is really the previous block */
+        if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
+        {
+            ERR("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
+                     (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           HEAP_IsRealArena  [Internal]
+ * Validates a block is a valid arena.
+ *
+ * RETURNS
+ *	TRUE: Success
+ *	FALSE: Failure
+ */
+static BOOL HEAP_IsRealArena( HEAP *heapPtr,   /* [in] ptr to the heap */
+              DWORD flags,   /* [in] Bit flags that control access during operation */
+              LPCVOID block, /* [in] Optional pointer to memory block to validate */
+              BOOL quiet )   /* [in] Flag - if true, HEAP_ValidateInUseArena
+                              *             does not complain    */
+{
+    SUBHEAP *subheap;
+    BOOL ret = TRUE;
+
+    if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
+    {
+        ERR("Invalid heap %p!\n", heapPtr );
+        return FALSE;
+    }
+
+    flags &= HEAP_NO_SERIALIZE;
+    flags |= heapPtr->flags;
+    /* calling HeapLock may result in infinite recursion, so do the critsect directly */
+    if (!(flags & HEAP_NO_SERIALIZE))
+        RtlEnterCriticalSection( &heapPtr->critSection );
+
+    if (block)
+    {
+        /* Only check this single memory block */
+
+        if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
+            ((char *)block < (char *)subheap + subheap->headerSize
+                              + sizeof(ARENA_INUSE)))
+        {
+            if (quiet == NOISY) 
+                ERR("Heap %p: block %p is not inside heap\n", heapPtr, block );
+            else if (WARN_ON(heap)) 
+                WARN("Heap %p: block %p is not inside heap\n", heapPtr, block );
+            ret = FALSE;
+        } else
+            ret = HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1, quiet );
+
+        if (!(flags & HEAP_NO_SERIALIZE))
+            RtlLeaveCriticalSection( &heapPtr->critSection );
+        return ret;
+    }
+
+    subheap = &heapPtr->subheap;
+    while (subheap && ret)
+    {
+        char *ptr = (char *)subheap + subheap->headerSize;
+        while (ptr < (char *)subheap + subheap->size)
+        {
+            if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+            {
+                if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) {
+                    ret = FALSE;
+                    break;
+                }
+                ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
+            }
+            else
+            {
+                if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) {
+                    ret = FALSE;
+                    break;
+                }
+                ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
+            }
+        }
+        subheap = subheap->next;
+    }
+
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+    return ret;
+}
+
+
+/***********************************************************************
+ *           RtlCreateHeap   (NTDLL.@)
+ */
+HANDLE WINAPI RtlCreateHeap( ULONG flags, PVOID addr, ULONG totalSize, ULONG commitSize,
+                             PVOID unknown, PRTL_HEAP_DEFINITION definition )
+{
+    SUBHEAP *subheap;
+
+    /* Allocate the heap block */
+
+    if (!totalSize)
+    {
+        totalSize = HEAP_DEF_SIZE;
+        flags |= HEAP_GROWABLE;
+    }
+    /* round up sizes */
+    totalSize  = (totalSize + 0xffff) & 0xffff0000;
+    commitSize = (commitSize + 0xffff) & 0xffff0000;
+    if (!commitSize) commitSize = 0x10000;
+    if (totalSize < commitSize) totalSize = commitSize;
+
+    if (!(subheap = HEAP_CreateSubHeap( NULL, addr, flags, commitSize, totalSize ))) return 0;
+
+    /* link it into the per-process heap list */
+    if (processHeap)
+    {
+        HEAP *heapPtr = subheap->heap;
+        RtlLockHeap( processHeap );
+        heapPtr->next = firstHeap;
+        firstHeap = heapPtr;
+        RtlUnlockHeap( processHeap );
+    }
+    else  /* assume the first heap we create is the process main heap */
+    {
+        set_process_heap( (HANDLE)subheap->heap );
+    }
+    return (HANDLE)subheap;
+}
+
+
+/***********************************************************************
+ *           RtlDestroyHeap   (NTDLL.@)
+ */
+HANDLE WINAPI RtlDestroyHeap( HANDLE heap )
+{
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+    SUBHEAP *subheap;
+
+    TRACE("%08x\n", heap );
+    if (!heapPtr) return heap;
+
+    if (heap == processHeap) return heap; /* cannot delete the main process heap */
+    else /* remove it from the per-process list */
+    {
+        HEAP **pptr;
+        RtlLockHeap( processHeap );
+        pptr = &firstHeap;
+        while (*pptr && *pptr != heapPtr) pptr = &(*pptr)->next;
+        if (*pptr) *pptr = (*pptr)->next;
+        RtlUnlockHeap( processHeap );
+    }
+
+    RtlDeleteCriticalSection( &heapPtr->critSection );
+    subheap = &heapPtr->subheap;
+    while (subheap)
+    {
+        SUBHEAP *next = subheap->next;
+        VirtualFree( subheap, 0, MEM_RELEASE );
+        subheap = next;
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           RtlAllocateHeap   (NTDLL.@)
+ *
+ * NOTE: does not set last error.
+ */
+PVOID WINAPI RtlAllocateHeap( HANDLE heap, ULONG flags, ULONG size )
+{
+    ARENA_FREE *pArena;
+    ARENA_INUSE *pInUse;
+    SUBHEAP *subheap;
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+
+    /* Validate the parameters */
+
+    if (!heapPtr) return NULL;
+    flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
+    flags |= heapPtr->flags;
+    size = (size + 3) & ~3;
+    if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
+
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+    /* Locate a suitable free block */
+
+    if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
+    {
+        TRACE("(%08x,%08lx,%08lx): returning NULL\n",
+                  heap, flags, size  );
+        if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+        if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
+        return NULL;
+    }
+
+    /* Remove the arena from the free list */
+
+    pArena->next->prev = pArena->prev;
+    pArena->prev->next = pArena->next;
+
+    /* Build the in-use arena */
+
+    pInUse = (ARENA_INUSE *)pArena;
+
+    /* in-use arena is smaller than free arena,
+     * so we have to add the difference to the size */
+    pInUse->size  = (pInUse->size & ~ARENA_FLAG_FREE) + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
+    pInUse->magic = ARENA_INUSE_MAGIC;
+
+    /* Shrink the block */
+
+    HEAP_ShrinkBlock( subheap, pInUse, size );
+
+    if (flags & HEAP_ZERO_MEMORY)
+        memset( pInUse + 1, 0, pInUse->size & ARENA_SIZE_MASK );
+    else if (TRACE_ON(heap))
+        memset( pInUse + 1, ARENA_INUSE_FILLER, pInUse->size & ARENA_SIZE_MASK );
+
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+    TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
+                  heap, flags, size, (DWORD)(pInUse + 1) );
+    return (LPVOID)(pInUse + 1);
+}
+
+
+/***********************************************************************
+ *           RtlFreeHeap   (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlFreeHeap( HANDLE heap, ULONG flags, PVOID ptr )
+{
+    ARENA_INUSE *pInUse;
+    SUBHEAP *subheap;
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+
+    /* Validate the parameters */
+
+    if (!ptr) return TRUE;  /* freeing a NULL ptr isn't an error in Win2k */
+    if (!heapPtr)
+    {
+        set_status( STATUS_INVALID_HANDLE );
+        return FALSE;
+    }
+
+    flags &= HEAP_NO_SERIALIZE;
+    flags |= heapPtr->flags;
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+    if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
+    {
+        if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+        set_status( STATUS_INVALID_PARAMETER );
+        TRACE("(%08x,%08lx,%08lx): returning FALSE\n",
+                      heap, flags, (DWORD)ptr );
+        return FALSE;
+    }
+
+    /* Turn the block into a free block */
+
+    pInUse  = (ARENA_INUSE *)ptr - 1;
+    subheap = HEAP_FindSubHeap( heapPtr, pInUse );
+    HEAP_MakeInUseBlockFree( subheap, pInUse );
+
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+    TRACE("(%08x,%08lx,%08lx): returning TRUE\n",
+                  heap, flags, (DWORD)ptr );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           RtlReAllocateHeap   (NTDLL.@)
+ */
+PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, ULONG size )
+{
+    ARENA_INUSE *pArena;
+    DWORD oldSize;
+    HEAP *heapPtr;
+    SUBHEAP *subheap;
+
+    if (!ptr) return RtlAllocateHeap( heap, flags, size );  /* FIXME: correct? */
+    if (!(heapPtr = HEAP_GetPtr( heap )))
+    {
+        set_status( STATUS_INVALID_HANDLE );
+        return FALSE;
+    }
+
+    /* Validate the parameters */
+
+    flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
+             HEAP_REALLOC_IN_PLACE_ONLY;
+    flags |= heapPtr->flags;
+    size = (size + 3) & ~3;
+    if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
+
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+    if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
+    {
+        if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+        set_status( STATUS_INVALID_PARAMETER );
+        TRACE("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
+                      heap, flags, (DWORD)ptr, size );
+        return NULL;
+    }
+
+    /* Check if we need to grow the block */
+
+    pArena = (ARENA_INUSE *)ptr - 1;
+    subheap = HEAP_FindSubHeap( heapPtr, pArena );
+    oldSize = (pArena->size & ARENA_SIZE_MASK);
+    if (size > oldSize)
+    {
+        char *pNext = (char *)(pArena + 1) + oldSize;
+        if ((pNext < (char *)subheap + subheap->size) &&
+            (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
+            (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
+        {
+            /* The next block is free and large enough */
+            ARENA_FREE *pFree = (ARENA_FREE *)pNext;
+            pFree->next->prev = pFree->prev;
+            pFree->prev->next = pFree->next;
+            pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
+            if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
+                                               + size + HEAP_MIN_BLOCK_SIZE))
+            {
+                if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+                if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
+                set_status( STATUS_NO_MEMORY );
+                return NULL;
+            }
+            HEAP_ShrinkBlock( subheap, pArena, size );
+        }
+        else  /* Do it the hard way */
+        {
+            ARENA_FREE *pNew;
+            ARENA_INUSE *pInUse;
+            SUBHEAP *newsubheap;
+
+            if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
+                !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
+            {
+                if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+                if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY );
+                set_status( STATUS_NO_MEMORY );
+                return NULL;
+            }
+
+            /* Build the in-use arena */
+
+            pNew->next->prev = pNew->prev;
+            pNew->prev->next = pNew->next;
+            pInUse = (ARENA_INUSE *)pNew;
+            pInUse->size = (pInUse->size & ~ARENA_FLAG_FREE)
+                           + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
+            pInUse->magic = ARENA_INUSE_MAGIC;
+            HEAP_ShrinkBlock( newsubheap, pInUse, size );
+            memcpy( pInUse + 1, pArena + 1, oldSize );
+
+            /* Free the previous block */
+
+            HEAP_MakeInUseBlockFree( subheap, pArena );
+            subheap = newsubheap;
+            pArena  = pInUse;
+        }
+    }
+    else HEAP_ShrinkBlock( subheap, pArena, size );  /* Shrink the block */
+
+    /* Clear the extra bytes if needed */
+
+    if (size > oldSize)
+    {
+        if (flags & HEAP_ZERO_MEMORY)
+            memset( (char *)(pArena + 1) + oldSize, 0,
+                    (pArena->size & ARENA_SIZE_MASK) - oldSize );
+        else if (TRACE_ON(heap))
+            memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
+                    (pArena->size & ARENA_SIZE_MASK) - oldSize );
+    }
+
+    /* Return the new arena */
+
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+    TRACE("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
+                  heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
+    return (LPVOID)(pArena + 1);
+}
+
+
+/***********************************************************************
+ *           RtlCompactHeap   (NTDLL.@)
+ */
+ULONG WINAPI RtlCompactHeap( HANDLE heap, ULONG flags )
+{
+    FIXME( "stub\n" );
+    return 0;
+}
+
+
+/***********************************************************************
+ *           RtlLockHeap   (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlLockHeap( HANDLE heap )
+{
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+    if (!heapPtr) return FALSE;
+    RtlEnterCriticalSection( &heapPtr->critSection );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           RtlUnlockHeap   (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlUnlockHeap( HANDLE heap )
+{
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+    if (!heapPtr) return FALSE;
+    RtlLeaveCriticalSection( &heapPtr->critSection );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           RtlSizeHeap   (NTDLL.@)
+ */
+ULONG WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, PVOID ptr )
+{
+    DWORD ret;
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+
+    if (!heapPtr)
+    {
+        set_status( STATUS_INVALID_HANDLE );
+        return (ULONG)-1;
+    }
+    flags &= HEAP_NO_SERIALIZE;
+    flags |= heapPtr->flags;
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection );
+    if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
+    {
+        set_status( STATUS_INVALID_PARAMETER );
+        ret = (ULONG)-1;
+    }
+    else
+    {
+        ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
+        ret = pArena->size & ARENA_SIZE_MASK;
+    }
+    if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection );
+
+    TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
+                  heap, flags, (DWORD)ptr, ret );
+    return ret;
+}
+
+
+/***********************************************************************
+ *           RtlValidateHeap   (NTDLL.@)
+ */
+BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, PCVOID block )
+{
+    HEAP *heapPtr = HEAP_GetPtr( heap );
+    if (!heapPtr) return FALSE;
+    return HEAP_IsRealArena( heapPtr, flags, block, QUIET );
+}
+
+
+/***********************************************************************
+ *           RtlWalkHeap    (NTDLL.@)
+ *
+ * FIXME: the PROCESS_HEAP_ENTRY flag values seem different between this
+ *        function and HeapWalk. To be checked.
+ */
+NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr )
+{
+    LPPROCESS_HEAP_ENTRY entry = entry_ptr; /* FIXME */
+    HEAP *heapPtr = HEAP_GetPtr(heap);
+    SUBHEAP *sub, *currentheap = NULL;
+    NTSTATUS ret;
+    char *ptr;
+    int region_index = 0;
+
+    FIXME( "not fully compatible\n" );
+
+    if (!heapPtr || !entry) return STATUS_INVALID_PARAMETER;
+
+    if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
+
+    /* set ptr to the next arena to be examined */
+
+    if (!entry->lpData) /* first call (init) ? */
+    {
+        TRACE("begin walking of heap 0x%08x.\n", heap);
+        currentheap = &heapPtr->subheap;
+        ptr = (char*)currentheap + currentheap->headerSize;
+    }
+    else
+    {
+        ptr = entry->lpData;
+        sub = &heapPtr->subheap;
+        while (sub)
+        {
+            if (((char *)ptr >= (char *)sub) &&
+                ((char *)ptr < (char *)sub + sub->size))
+            {
+                currentheap = sub;
+                break;
+            }
+            sub = sub->next;
+            region_index++;
+        }
+        if (currentheap == NULL)
+        {
+            ERR("no matching subheap found, shouldn't happen !\n");
+            ret = STATUS_NO_MORE_ENTRIES;
+            goto HW_end;
+        }
+
+        ptr += entry->cbData; /* point to next arena */
+        if (ptr > (char *)currentheap + currentheap->size - 1)
+        {   /* proceed with next subheap */
+            if (!(currentheap = currentheap->next))
+            {  /* successfully finished */
+                TRACE("end reached.\n");
+                ret = STATUS_NO_MORE_ENTRIES;
+                goto HW_end;
+            }
+            ptr = (char*)currentheap + currentheap->headerSize;
+        }
+    }
+
+    entry->wFlags = 0;
+    if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+    {
+        ARENA_FREE *pArena = (ARENA_FREE *)ptr;
+
+        /*TRACE("free, magic: %04x\n", pArena->magic);*/
+
+        entry->lpData = pArena + 1;
+        entry->cbData = pArena->size & ARENA_SIZE_MASK;
+        entry->cbOverhead = sizeof(ARENA_FREE);
+        entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
+    }
+    else
+    {
+        ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
+
+        /*TRACE("busy, magic: %04x\n", pArena->magic);*/
+
+        entry->lpData = pArena + 1;
+        entry->cbData = pArena->size & ARENA_SIZE_MASK;
+        entry->cbOverhead = sizeof(ARENA_INUSE);
+        entry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
+        /* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
+        and PROCESS_HEAP_ENTRY_DDESHARE yet */
+    }
+
+    entry->iRegionIndex = region_index;
+
+    /* first element of heap ? */
+    if (ptr == (char *)(currentheap + currentheap->headerSize))
+    {
+        entry->wFlags |= PROCESS_HEAP_REGION;
+        entry->u.Region.dwCommittedSize = currentheap->commitSize;
+        entry->u.Region.dwUnCommittedSize =
+                currentheap->size - currentheap->commitSize;
+        entry->u.Region.lpFirstBlock = /* first valid block */
+                currentheap + currentheap->headerSize;
+        entry->u.Region.lpLastBlock  = /* first invalid block */
+                currentheap + currentheap->size;
+    }
+    ret = STATUS_SUCCESS;
+
+HW_end:
+    if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
+    return ret;
+}
+
+
+/***********************************************************************
+ *           RtlGetProcessHeaps    (NTDLL.@)
+ */
+ULONG WINAPI RtlGetProcessHeaps( ULONG count, HANDLE *heaps )
+{
+    DWORD total;
+    HEAP *ptr;
+
+    if (!processHeap) return 0;  /* should never happen */
+    total = 1;  /* main heap */
+    RtlLockHeap( processHeap );
+    for (ptr = firstHeap; ptr; ptr = ptr->next) total++;
+    if (total <= count)
+    {
+        *heaps++ = (HANDLE)processHeap;
+        for (ptr = firstHeap; ptr; ptr = ptr->next) *heaps++ = (HANDLE)ptr;
+    }
+    RtlUnlockHeap( processHeap );
+    return total;
+}
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 3ac3485..8e055fa 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -300,7 +300,7 @@
 @ stub RtlCheckRegistryKey
 @ stub RtlClearAllBits
 @ stdcall RtlClearBits(long long long) RtlClearBits
-@ stub RtlCompactHeap
+@ stdcall RtlCompactHeap(long long) RtlCompactHeap
 @ stdcall RtlCompareMemory(ptr ptr long) RtlCompareMemory
 @ stub RtlCompareMemoryUlong
 @ stdcall RtlCompareString(ptr ptr long) RtlCompareString
@@ -406,7 +406,7 @@
 @ stub RtlGetNtGlobalFlags
 @ stdcall RtlGetNtProductType(ptr) RtlGetNtProductType
 @ stdcall RtlGetOwnerSecurityDescriptor(ptr ptr ptr) RtlGetOwnerSecurityDescriptor
-@ stub RtlGetProcessHeaps
+@ stdcall RtlGetProcessHeaps(long ptr) RtlGetProcessHeaps
 @ stdcall RtlGetSaclSecurityDescriptor(ptr ptr ptr ptr)RtlGetSaclSecurityDescriptor
 @ stub RtlGetUserInfoHeap
 @ stdcall RtlIdentifierAuthoritySid(ptr) RtlIdentifierAuthoritySid
@@ -446,7 +446,7 @@
 @ stdcall RtlLengthSecurityDescriptor(ptr) RtlLengthSecurityDescriptor
 @ stdcall RtlLengthSid(ptr) RtlLengthSid
 @ stub RtlLocalTimeToSystemTime
-@ stub RtlLockHeap
+@ stdcall RtlLockHeap(long) RtlLockHeap
 @ stub RtlLookupElementGenericTable
 @ stdcall RtlMakeSelfRelativeSD(ptr ptr ptr) RtlMakeSelfRelativeSD
 @ stub RtlMapGenericMask
@@ -482,7 +482,7 @@
 @ stdcall RtlRaiseException(ptr) RtlRaiseException
 @ stdcall RtlRaiseStatus(long) RtlRaiseStatus
 @ stub RtlRandom
-@ stub RtlReAllocateHeap
+@ stdcall RtlReAllocateHeap(long long ptr long) RtlReAllocateHeap
 @ stub RtlRealPredecessor
 @ stub RtlRealSuccessor
 @ stdcall RtlReleasePebLock() RtlReleasePebLock
@@ -508,7 +508,7 @@
 @ stub RtlSetTimeZoneInformation
 @ stub RtlSetUserFlagsHeap
 @ stub RtlSetUserValueHeap
-@ stdcall RtlSizeHeap(long long long) HeapSize
+@ stdcall RtlSizeHeap(long long ptr) RtlSizeHeap
 @ stub RtlSplay
 @ stub RtlStartRXact
 @ stdcall RtlSubAuthorityCountSid(ptr) RtlSubAuthorityCountSid
@@ -532,7 +532,7 @@
 @ stdcall RtlUnicodeToMultiByteSize(ptr wstr long) RtlUnicodeToMultiByteSize
 @ stdcall RtlUnicodeToOemN(ptr long ptr ptr long) RtlUnicodeToOemN
 @ stub RtlUniform
-@ stub RtlUnlockHeap
+@ stdcall RtlUnlockHeap(long) RtlUnlockHeap
 @ stdcall RtlUnwind(ptr ptr ptr long) RtlUnwind
 @ stub RtlUpcaseUnicodeChar
 @ stdcall RtlUpcaseUnicodeString(ptr ptr long) RtlUpcaseUnicodeString
@@ -548,9 +548,9 @@
 @ stub RtlValidAcl
 @ stdcall RtlValidSecurityDescriptor(ptr) RtlValidSecurityDescriptor
 @ stdcall RtlValidSid(ptr) RtlValidSid
-@ stub RtlValidateHeap
+@ stdcall RtlValidateHeap(long long ptr) RtlValidateHeap
 @ stub RtlValidateProcessHeaps
-@ stub RtlWalkHeap
+@ stdcall RtlWalkHeap(long ptr) RtlWalkHeap
 @ stub RtlWriteRegistryValue
 @ stub RtlZeroHeap
 @ stdcall RtlZeroMemory(ptr long) RtlZeroMemory
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c
index 4311ea2..a6cf39d 100644
--- a/dlls/ntdll/rtl.c
+++ b/dlls/ntdll/rtl.c
@@ -213,64 +213,6 @@
 }
 
 /*
- *	heap functions
- */
-
-/******************************************************************************
- *  RtlCreateHeap		[NTDLL.@]
- */
-HANDLE WINAPI RtlCreateHeap(
-	ULONG Flags,
-	PVOID BaseAddress,
-	ULONG SizeToReserve,
-	ULONG SizeToCommit,
-	PVOID Unknown,
-	PRTL_HEAP_DEFINITION Definition)
-{
-	FIXME("(0x%08lx, %p, 0x%08lx, 0x%08lx, %p, %p) semi-stub\n",
-	Flags, BaseAddress, SizeToReserve, SizeToCommit, Unknown, Definition);
-	
-	return HeapCreate ( Flags, SizeToCommit, SizeToReserve);
-
-}	
-/******************************************************************************
- *  RtlAllocateHeap		[NTDLL.@]
- */
-PVOID WINAPI RtlAllocateHeap(
-	HANDLE Heap,
-	ULONG Flags,
-	ULONG Size)
-{
-	TRACE("(0x%08x, 0x%08lx, 0x%08lx) semi stub\n",
-	Heap, Flags, Size);
-	return HeapAlloc(Heap, Flags, Size);
-}
-
-/******************************************************************************
- *  RtlFreeHeap		[NTDLL.@]
- */
-BOOLEAN WINAPI RtlFreeHeap(
-	HANDLE Heap,
-	ULONG Flags,
-	PVOID Address)
-{
-	TRACE("(0x%08x, 0x%08lx, %p) semi stub\n",
-	Heap, Flags, Address);
-	return HeapFree(Heap, Flags, Address);
-}
-	
-/******************************************************************************
- *  RtlDestroyHeap		[NTDLL.@]
- */
-HANDLE WINAPI RtlDestroyHeap(
-	HANDLE Heap)
-{
-	TRACE("(0x%08x) semi stub\n", Heap);
-	if (!HeapDestroy(Heap)) return Heap;
-        return 0;
-}
-	
-/*
  *	misc functions
  */
 
diff --git a/dlls/ole32/ifs.c b/dlls/ole32/ifs.c
index 6d8c042..6531d4a 100644
--- a/dlls/ole32/ifs.c
+++ b/dlls/ole32/ifs.c
@@ -143,25 +143,32 @@
 SEGPTR WINAPI IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) {
         ICOM_THIS(IMalloc16Impl,iface);
 	TRACE("(%p)->Alloc(%ld)\n",This,cb);
-        return MapLS( HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, cb ) );
+        return MapLS( HeapAlloc( GetProcessHeap(), 0, cb ) );
 }
 
 /******************************************************************************
  * IMalloc16_Realloc [COMPOBJ.504]
  */
-SEGPTR WINAPI IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) {
-        ICOM_THIS(IMalloc16Impl,iface);
-        TRACE("(%p)->Realloc(%08lx,%ld)\n",This,pv,cb);
-        return MapLS( HeapReAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, MapSL(pv), cb ) );
+SEGPTR WINAPI IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb)
+{
+    SEGPTR ret;
+    ICOM_THIS(IMalloc16Impl,iface);
+    TRACE("(%p)->Realloc(%08lx,%ld)\n",This,pv,cb);
+    ret = MapLS( HeapReAlloc( GetProcessHeap(), 0, MapSL(pv), cb ) );
+    UnMapLS(pv);
+    return ret;
 }
 
 /******************************************************************************
  * IMalloc16_Free [COMPOBJ.505]
  */
-VOID WINAPI IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) {
-        ICOM_THIS(IMalloc16Impl,iface);
-        TRACE("(%p)->Free(%08lx)\n",This,pv);
-        HeapFree( GetProcessHeap(), HEAP_WINE_SEGPTR, MapSL(pv) );
+VOID WINAPI IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv)
+{
+    void *ptr = MapSL(pv);
+    ICOM_THIS(IMalloc16Impl,iface);
+    TRACE("(%p)->Free(%08lx)\n",This,pv);
+    UnMapLS(pv);
+    HeapFree( GetProcessHeap(), 0, ptr );
 }
 
 /******************************************************************************
@@ -171,7 +178,7 @@
 {
 	ICOM_CTHIS(IMalloc16Impl,iface);
         TRACE("(%p)->GetSize(%08lx)\n",This,pv);
-        return HeapSize( GetProcessHeap(), HEAP_WINE_SEGPTR, MapSL(pv) );
+        return HeapSize( GetProcessHeap(), 0, MapSL(pv) );
 }
 
 /******************************************************************************
diff --git a/graphics/win16drv/font.c b/graphics/win16drv/font.c
index b6ad490..5ebe6e1 100644
--- a/graphics/win16drv/font.c
+++ b/graphics/win16drv/font.c
@@ -95,7 +95,7 @@
                                   &physDev->lf, 0, 0); 
 
     if( physDev->FontInfo && 
-	HeapSize( GetProcessHeap(), HEAP_WINE_SEGPTR, physDev->FontInfo ) < nSize )
+	HeapSize( GetProcessHeap(), 0, physDev->FontInfo ) < nSize )
     {
         SEGPTR_FREE( physDev->FontInfo );
 	physDev->FontInfo = NULL;
diff --git a/include/heap.h b/include/heap.h
index b9fc6fc..4830554 100644
--- a/include/heap.h
+++ b/include/heap.h
@@ -14,18 +14,16 @@
 #include "wine/unicode.h"
 #include "wine/windef16.h"  /* for SEGPTR */
 
-extern SEGPTR HEAP_GetSegptr( HANDLE heap, DWORD flags, LPCVOID ptr );
-
 /* SEGPTR helper macros */
 
 #define SEGPTR_ALLOC(size) \
-     (HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, (size) ))
+     (HeapAlloc( GetProcessHeap(), 0, (size) ))
 #define SEGPTR_NEW(type) \
-     ((type *)HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, sizeof(type) ))
+     ((type *)HeapAlloc( GetProcessHeap(), 0, sizeof(type) ))
 #define SEGPTR_STRDUP_WtoA(str) \
-     (HIWORD(str) ? HEAP_strdupWtoA( GetProcessHeap(), HEAP_WINE_SEGPTR, (str) ) : (LPSTR)(str))
+     (HIWORD(str) ? HEAP_strdupWtoA( GetProcessHeap(), 0, (str) ) : (LPSTR)(str))
 #define SEGPTR_FREE(ptr) \
-     (HIWORD(ptr) ? HeapFree( GetProcessHeap(), HEAP_WINE_SEGPTR, (ptr) ) : 0)
+     (HIWORD(ptr) ? HeapFree( GetProcessHeap(), 0, (ptr) ) : 0)
 #define SEGPTR_GET(ptr) MapLS(ptr)
 
 inline static LPSTR SEGPTR_STRDUP( LPCSTR str )
@@ -33,7 +31,7 @@
     if (HIWORD(str))
     {
         INT len = strlen(str) + 1;
-        LPSTR p = HeapAlloc( GetProcessHeap(), HEAP_WINE_SEGPTR, len );
+        LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
         if (p) memcpy( p, str, len );
         return p;
     }
diff --git a/include/ntddk.h b/include/ntddk.h
index 9977c51..a4cd777 100644
--- a/include/ntddk.h
+++ b/include/ntddk.h
@@ -723,6 +723,7 @@
 ULONG     WINAPI RtlSizeHeap(HANDLE,ULONG,PVOID);
 BOOLEAN   WINAPI RtlValidateHeap(HANDLE,ULONG,PCVOID);
 ULONG     WINAPI RtlGetProcessHeaps(ULONG,HANDLE*);
+NTSTATUS  WINAPI RtlWalkHeap(HANDLE,PVOID);
 
 /*	exception */
 
diff --git a/include/winbase.h b/include/winbase.h
index 9355baf..388dda8 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -985,20 +985,33 @@
 
 /*int WinMain(HINSTANCE, HINSTANCE prev, char *cmd, int show);*/
 
-LONG WINAPI RtlEnterCriticalSection( CRITICAL_SECTION *crit );
-LONG WINAPI RtlLeaveCriticalSection( CRITICAL_SECTION *crit );
-LONG WINAPI RtlDeleteCriticalSection( CRITICAL_SECTION *crit );
-BOOL WINAPI RtlTryEnterCriticalSection( CRITICAL_SECTION *crit );
-/* FIXME: need to use defines because we don't have proper imports yet */
+/* FIXME: need to use defines because we don't have proper imports everywhere yet */
+#ifndef have_proper_imports
+LONG        WINAPI RtlEnterCriticalSection( CRITICAL_SECTION *crit );
+LONG        WINAPI RtlLeaveCriticalSection( CRITICAL_SECTION *crit );
+LONG        WINAPI RtlDeleteCriticalSection( CRITICAL_SECTION *crit );
+BOOL        WINAPI RtlTryEnterCriticalSection( CRITICAL_SECTION *crit );
+PVOID       WINAPI RtlAllocateHeap(HANDLE,ULONG,ULONG);
+BOOLEAN     WINAPI RtlFreeHeap(HANDLE,ULONG,PVOID);
+PVOID       WINAPI RtlReAllocateHeap(HANDLE,ULONG,PVOID,ULONG);
+ULONG       WINAPI RtlSizeHeap(HANDLE,ULONG,PVOID);
+#define     HeapAlloc(heap,flags,size) RtlAllocateHeap(heap,flags,size)
+#define     HeapFree(heap,flags,ptr) RtlFreeHeap(heap,flags,ptr)
+#define     HeapReAlloc(heap,flags,ptr,size) RtlReAllocateHeap(heap,flags,ptr,size)
+#define     HeapSize(heap,flags,ptr) RtlSizeHeap(heap,flags,ptr)
 #define     EnterCriticalSection(crit) RtlEnterCriticalSection(crit)
 #define     LeaveCriticalSection(crit) RtlLeaveCriticalSection(crit)
 #define     DeleteCriticalSection(crit) RtlDeleteCriticalSection(crit)
 #define     TryEnterCriticalSection(crit) RtlTryEnterCriticalSection(crit)
-#if 0
-void      WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit);
-void      WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit);
-BOOL      WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit);
-void      WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit);
+#else
+LPVOID      WINAPI HeapAlloc(HANDLE,DWORD,DWORD);
+BOOL        WINAPI HeapFree(HANDLE,DWORD,LPVOID);
+LPVOID      WINAPI HeapReAlloc(HANDLE,DWORD,LPVOID,DWORD);
+DWORD       WINAPI HeapSize(HANDLE,DWORD,LPVOID);
+void        WINAPI DeleteCriticalSection(CRITICAL_SECTION *lpCrit);
+void        WINAPI EnterCriticalSection(CRITICAL_SECTION *lpCrit);
+BOOL        WINAPI TryEnterCriticalSection(CRITICAL_SECTION *lpCrit);
+void        WINAPI LeaveCriticalSection(CRITICAL_SECTION *lpCrit);
 #endif
 
 void      WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit);
@@ -1237,14 +1250,10 @@
 BOOL        WINAPI GetUserNameW(LPWSTR,LPDWORD);
 #define     GetUserName WINELIB_NAME_AW(GetUserName)
 VOID        WINAPI GlobalMemoryStatus(LPMEMORYSTATUS);
-LPVOID      WINAPI HeapAlloc(HANDLE,DWORD,DWORD);
 DWORD       WINAPI HeapCompact(HANDLE,DWORD);
 HANDLE    WINAPI HeapCreate(DWORD,DWORD,DWORD);
 BOOL      WINAPI HeapDestroy(HANDLE);
-BOOL      WINAPI HeapFree(HANDLE,DWORD,LPVOID);
 BOOL      WINAPI HeapLock(HANDLE);
-LPVOID      WINAPI HeapReAlloc(HANDLE,DWORD,LPVOID,DWORD);
-DWORD       WINAPI HeapSize(HANDLE,DWORD,LPVOID);
 BOOL      WINAPI HeapUnlock(HANDLE);
 BOOL      WINAPI HeapValidate(HANDLE,DWORD,LPCVOID);
 BOOL        WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY);
diff --git a/include/winnt.h b/include/winnt.h
index 172fa55..5064e50 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -524,11 +524,7 @@
 
 /* This flag allows it to create heaps shared by all processes under win95,
    FIXME: correct name */
-#define HEAP_SHARED                     0x04000000  
-
-#define HEAP_WINE_SEGPTR                0x10000000  /* Not a Win32 flag */
-#define HEAP_WINE_CODESEG               0x20000000  /* Not a Win32 flag */
-#define HEAP_WINE_CODE16SEG             0x40000000  /* Not a Win32 flag */
+#define HEAP_SHARED                     0x04000000
 
 /* Processor feature flags.  */
 #define PF_FLOATING_POINT_PRECISION_ERRATA	0
diff --git a/memory/heap.c b/memory/heap.c
index 9942330..bcf501f 100644
--- a/memory/heap.c
+++ b/memory/heap.c
@@ -12,1668 +12,24 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "winbase.h"
 #include "wine/winbase16.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "ntddk.h"
 #include "wine/unicode.h"
 #include "selectors.h"
 #include "global.h"
-#include "winbase.h"
-#include "winerror.h"
-#include "winnt.h"
-#include "heap.h"
+#include "thread.h"
 #include "toolhelp.h"
 #include "debugtools.h"
-#include "winnls.h"
 
 DEFAULT_DEBUG_CHANNEL(heap);
 
-/* Note: the heap data structures are based on what Pietrek describes in his
- * book 'Windows 95 System Programming Secrets'. The layout is not exactly
- * the same, but could be easily adapted if it turns out some programs
- * require it.
- */
-
-typedef struct tagARENA_INUSE
-{
-    DWORD  size;                    /* Block size; must be the first field */
-    WORD   magic;                   /* Magic number */
-    WORD   threadId;                /* Allocating thread id */
-    void  *callerEIP;               /* EIP of caller upon allocation */
-} ARENA_INUSE;
-
-typedef struct tagARENA_FREE
-{
-    DWORD                 size;     /* Block size; must be the first field */
-    WORD                  magic;    /* Magic number */
-    WORD                  threadId; /* Freeing thread id */
-    struct tagARENA_FREE *next;     /* Next free arena */
-    struct tagARENA_FREE *prev;     /* Prev free arena */
-} ARENA_FREE;
-
-#define ARENA_FLAG_FREE        0x00000001  /* flags OR'ed with arena size */
-#define ARENA_FLAG_PREV_FREE   0x00000002
-#define ARENA_SIZE_MASK        0xfffffffc
-#define ARENA_INUSE_MAGIC      0x4842      /* Value for arena 'magic' field */
-#define ARENA_FREE_MAGIC       0x4846      /* Value for arena 'magic' field */
-
-#define ARENA_INUSE_FILLER     0x55
-#define ARENA_FREE_FILLER      0xaa
-
-#define QUIET                  1           /* Suppress messages  */
-#define NOISY                  0           /* Report all errors  */
-
-#define HEAP_NB_FREE_LISTS   4   /* Number of free lists */
-
-/* Max size of the blocks on the free lists */
-static const DWORD HEAP_freeListSizes[HEAP_NB_FREE_LISTS] =
-{
-    0x20, 0x80, 0x200, 0xffffffff
-};
-
-typedef struct
-{
-    DWORD       size;
-    ARENA_FREE  arena;
-} FREE_LIST_ENTRY;
-
-struct tagHEAP;
-
-typedef struct tagSUBHEAP
-{
-    DWORD               size;       /* Size of the whole sub-heap */
-    DWORD               commitSize; /* Committed size of the sub-heap */
-    DWORD               headerSize; /* Size of the heap header */
-    struct tagSUBHEAP  *next;       /* Next sub-heap */
-    struct tagHEAP     *heap;       /* Main heap structure */
-    DWORD               magic;      /* Magic number */
-    WORD                selector;   /* Selector for HEAP_WINE_SEGPTR heaps */
-} SUBHEAP;
-
-#define SUBHEAP_MAGIC    ((DWORD)('S' | ('U'<<8) | ('B'<<16) | ('H'<<24)))
-
-typedef struct tagHEAP
-{
-    SUBHEAP          subheap;       /* First sub-heap */
-    struct tagHEAP  *next;          /* Next heap for this process */
-    FREE_LIST_ENTRY  freeList[HEAP_NB_FREE_LISTS];  /* Free lists */
-    CRITICAL_SECTION critSection;   /* Critical section for serialization */
-    DWORD            flags;         /* Heap flags */
-    DWORD            magic;         /* Magic number */
-} HEAP;
-
-#define HEAP_MAGIC       ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24)))
-
-#define HEAP_DEF_SIZE        0x110000   /* Default heap size = 1Mb + 64Kb */
-#define HEAP_MIN_BLOCK_SIZE  (8+sizeof(ARENA_FREE))  /* Min. heap block size */
-#define COMMIT_MASK          0xffff  /* bitmask for commit/decommit granularity */
-
-static HEAP *systemHeap;   /* globally shared heap */
-static HEAP *processHeap;  /* main process heap */
-static HEAP *segptrHeap;   /* main segptr heap */
-static HEAP *firstHeap;    /* head of secondary heaps list */
-
 /* address where we try to map the system heap */
 #define SYSTEM_HEAP_BASE  ((void*)0x65430000)
-
-static BOOL HEAP_IsRealArena( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet );
-
-#ifdef __GNUC__
-#define GET_EIP()    (__builtin_return_address(0))
-#define SET_EIP(ptr) ((ARENA_INUSE*)(ptr) - 1)->callerEIP = GET_EIP()
-#else
-#define GET_EIP()    0
-#define SET_EIP(ptr) /* nothing */
-#endif  /* __GNUC__ */
-
-/***********************************************************************
- *           HEAP_Dump
- */
-void HEAP_Dump( HEAP *heap )
-{
-    int i;
-    SUBHEAP *subheap;
-    char *ptr;
-
-    DPRINTF( "Heap: %08lx\n", (DWORD)heap );
-    DPRINTF( "Next: %08lx  Sub-heaps: %08lx",
-	  (DWORD)heap->next, (DWORD)&heap->subheap );
-    subheap = &heap->subheap;
-    while (subheap->next)
-    {
-        DPRINTF( " -> %08lx", (DWORD)subheap->next );
-        subheap = subheap->next;
-    }
-
-    DPRINTF( "\nFree lists:\n Block   Stat   Size    Id\n" );
-    for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
-        DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
-	      (DWORD)&heap->freeList[i].arena, heap->freeList[i].arena.size,
-	      heap->freeList[i].arena.threadId,
-	      (DWORD)heap->freeList[i].arena.prev,
-	      (DWORD)heap->freeList[i].arena.next );
-
-    subheap = &heap->subheap;
-    while (subheap)
-    {
-        DWORD freeSize = 0, usedSize = 0, arenaSize = subheap->headerSize;
-        DPRINTF( "\n\nSub-heap %08lx: size=%08lx committed=%08lx\n",
-	      (DWORD)subheap, subheap->size, subheap->commitSize );
-	
-        DPRINTF( "\n Block   Stat   Size    Id\n" );
-        ptr = (char*)subheap + subheap->headerSize;
-        while (ptr < (char *)subheap + subheap->size)
-        {
-            if (*(DWORD *)ptr & ARENA_FLAG_FREE)
-            {
-                ARENA_FREE *pArena = (ARENA_FREE *)ptr;
-                DPRINTF( "%08lx free %08lx %04x prev=%08lx next=%08lx\n",
-		      (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
-		      pArena->threadId, (DWORD)pArena->prev,
-		      (DWORD)pArena->next);
-                ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
-                arenaSize += sizeof(ARENA_FREE);
-                freeSize += pArena->size & ARENA_SIZE_MASK;
-            }
-            else if (*(DWORD *)ptr & ARENA_FLAG_PREV_FREE)
-            {
-                ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
-                DPRINTF( "%08lx Used %08lx %04x back=%08lx EIP=%p\n",
-		      (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
-		      pArena->threadId, *((DWORD *)pArena - 1),
-		      pArena->callerEIP );
-                ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
-                arenaSize += sizeof(ARENA_INUSE);
-                usedSize += pArena->size & ARENA_SIZE_MASK;
-            }
-            else
-            {
-                ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
-                DPRINTF( "%08lx used %08lx %04x EIP=%p\n",
-		      (DWORD)pArena, pArena->size & ARENA_SIZE_MASK,
-		      pArena->threadId, pArena->callerEIP );
-                ptr += sizeof(*pArena) + (pArena->size & ARENA_SIZE_MASK);
-                arenaSize += sizeof(ARENA_INUSE);
-                usedSize += pArena->size & ARENA_SIZE_MASK;
-            }
-        }
-        DPRINTF( "\nTotal: Size=%08lx Committed=%08lx Free=%08lx Used=%08lx Arenas=%08lx (%ld%%)\n\n",
-	      subheap->size, subheap->commitSize, freeSize, usedSize,
-	      arenaSize, (arenaSize * 100) / subheap->size );
-        subheap = subheap->next;
-    }
-}
-
-
-/***********************************************************************
- *           HEAP_GetPtr
- * RETURNS
- *	Pointer to the heap
- *	NULL: Failure
- */
-static HEAP *HEAP_GetPtr(
-             HANDLE heap /* [in] Handle to the heap */
-) {
-    HEAP *heapPtr = (HEAP *)heap;
-    if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
-    {
-        ERR("Invalid heap %08x!\n", heap );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return NULL;
-    }
-    if (TRACE_ON(heap) && !HEAP_IsRealArena( heapPtr, 0, NULL, NOISY ))
-    {
-        HEAP_Dump( heapPtr );
-        assert( FALSE );
-        SetLastError( ERROR_INVALID_HANDLE );
-        return NULL;
-    }
-    return heapPtr;
-}
-
-
-/***********************************************************************
- *           HEAP_InsertFreeBlock
- *
- * Insert a free block into the free list.
- */
-static void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena )
-{
-    FREE_LIST_ENTRY *pEntry = heap->freeList;
-    while (pEntry->size < pArena->size) pEntry++;
-    pArena->size      |= ARENA_FLAG_FREE;
-    pArena->next       = pEntry->arena.next;
-    pArena->next->prev = pArena;
-    pArena->prev       = &pEntry->arena;
-    pEntry->arena.next = pArena;
-}
-
-
-/***********************************************************************
- *           HEAP_FindSubHeap
- * Find the sub-heap containing a given address.
- *
- * RETURNS
- *	Pointer: Success
- *	NULL: Failure
- */
-static SUBHEAP *HEAP_FindSubHeap(
-                HEAP *heap, /* [in] Heap pointer */
-                LPCVOID ptr /* [in] Address */
-) {
-    SUBHEAP *sub = &heap->subheap;
-    while (sub)
-    {
-        if (((char *)ptr >= (char *)sub) &&
-            ((char *)ptr < (char *)sub + sub->size)) return sub;
-        sub = sub->next;
-    }
-    return NULL;
-}
-
-
-/***********************************************************************
- *           HEAP_Commit
- *
- * Make sure the heap storage is committed up to (not including) ptr.
- */
-static inline BOOL HEAP_Commit( SUBHEAP *subheap, void *ptr )
-{
-    DWORD size = (DWORD)((char *)ptr - (char *)subheap);
-    size = (size + COMMIT_MASK) & ~COMMIT_MASK;
-    if (size > subheap->size) size = subheap->size;
-    if (size <= subheap->commitSize) return TRUE;
-    if (!VirtualAlloc( (char *)subheap + subheap->commitSize,
-                       size - subheap->commitSize, MEM_COMMIT,
-                       PAGE_EXECUTE_READWRITE))
-    {
-        WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n",
-                 size - subheap->commitSize,
-                 (DWORD)((char *)subheap + subheap->commitSize),
-                 (DWORD)subheap->heap );
-        return FALSE;
-    }
-    subheap->commitSize = size;
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HEAP_Decommit
- *
- * If possible, decommit the heap storage from (including) 'ptr'.
- */
-static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
-{
-    DWORD size = (DWORD)((char *)ptr - (char *)subheap);
-    /* round to next block and add one full block */
-    size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1;
-    if (size >= subheap->commitSize) return TRUE;
-    if (!VirtualFree( (char *)subheap + size,
-                      subheap->commitSize - size, MEM_DECOMMIT ))
-    {
-        WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
-                 subheap->commitSize - size,
-                 (DWORD)((char *)subheap + size),
-                 (DWORD)subheap->heap );
-        return FALSE;
-    }
-    subheap->commitSize = size;
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HEAP_CreateFreeBlock
- *
- * Create a free block at a specified address. 'size' is the size of the
- * whole block, including the new arena.
- */
-static void HEAP_CreateFreeBlock( SUBHEAP *subheap, void *ptr, DWORD size )
-{
-    ARENA_FREE *pFree;
-
-    /* Create a free arena */
-
-    pFree = (ARENA_FREE *)ptr;
-    pFree->threadId = GetCurrentTask();
-    pFree->magic = ARENA_FREE_MAGIC;
-
-    /* If debugging, erase the freed block content */
-
-    if (TRACE_ON(heap))
-    {
-        char *pEnd = (char *)ptr + size;
-        if (pEnd > (char *)subheap + subheap->commitSize)
-            pEnd = (char *)subheap + subheap->commitSize;
-        if (pEnd > (char *)(pFree + 1))
-            memset( pFree + 1, ARENA_FREE_FILLER, pEnd - (char *)(pFree + 1) );
-    }
-
-    /* Check if next block is free also */
-
-    if (((char *)ptr + size < (char *)subheap + subheap->size) &&
-        (*(DWORD *)((char *)ptr + size) & ARENA_FLAG_FREE))
-    {
-        /* Remove the next arena from the free list */
-        ARENA_FREE *pNext = (ARENA_FREE *)((char *)ptr + size);
-        pNext->next->prev = pNext->prev;
-        pNext->prev->next = pNext->next;
-        size += (pNext->size & ARENA_SIZE_MASK) + sizeof(*pNext);
-        if (TRACE_ON(heap))
-            memset( pNext, ARENA_FREE_FILLER, sizeof(ARENA_FREE) );
-    }
-
-    /* Set the next block PREV_FREE flag and pointer */
-
-    if ((char *)ptr + size < (char *)subheap + subheap->size)
-    {
-        DWORD *pNext = (DWORD *)((char *)ptr + size);
-        *pNext |= ARENA_FLAG_PREV_FREE;
-        *(ARENA_FREE **)(pNext - 1) = pFree;
-    }
-
-    /* Last, insert the new block into the free list */
-
-    pFree->size = size - sizeof(*pFree);
-    HEAP_InsertFreeBlock( subheap->heap, pFree );
-}
-
-
-/***********************************************************************
- *           HEAP_MakeInUseBlockFree
- *
- * Turn an in-use block into a free block. Can also decommit the end of
- * the heap, and possibly even free the sub-heap altogether.
- */
-static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
-{
-    ARENA_FREE *pFree;
-    DWORD size = (pArena->size & ARENA_SIZE_MASK) + sizeof(*pArena);
-
-    /* Check if we can merge with previous block */
-
-    if (pArena->size & ARENA_FLAG_PREV_FREE)
-    {
-        pFree = *((ARENA_FREE **)pArena - 1);
-        size += (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
-        /* Remove it from the free list */
-        pFree->next->prev = pFree->prev;
-        pFree->prev->next = pFree->next;
-    }
-    else pFree = (ARENA_FREE *)pArena;
-
-    /* Create a free block */
-
-    HEAP_CreateFreeBlock( subheap, pFree, size );
-    size = (pFree->size & ARENA_SIZE_MASK) + sizeof(ARENA_FREE);
-    if ((char *)pFree + size < (char *)subheap + subheap->size)
-        return;  /* Not the last block, so nothing more to do */
-
-    /* Free the whole sub-heap if it's empty and not the original one */
-
-    if (((char *)pFree == (char *)subheap + subheap->headerSize) &&
-        (subheap != &subheap->heap->subheap))
-    {
-        SUBHEAP *pPrev = &subheap->heap->subheap;
-        /* Remove the free block from the list */
-        pFree->next->prev = pFree->prev;
-        pFree->prev->next = pFree->next;
-        /* Remove the subheap from the list */
-        while (pPrev && (pPrev->next != subheap)) pPrev = pPrev->next;
-        if (pPrev) pPrev->next = subheap->next;
-        /* Free the memory */
-        subheap->magic = 0;
-        if (subheap->selector) FreeSelector16( subheap->selector );
-        VirtualFree( subheap, 0, MEM_RELEASE );
-        return;
-    }
-    
-    /* Decommit the end of the heap */
-
-    if (!(subheap->heap->flags & HEAP_SHARED)) HEAP_Decommit( subheap, pFree + 1 );
-}
-
-
-/***********************************************************************
- *           HEAP_ShrinkBlock
- *
- * Shrink an in-use block.
- */
-static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, DWORD size)
-{
-    if ((pArena->size & ARENA_SIZE_MASK) >= size + HEAP_MIN_BLOCK_SIZE)
-    {
-        HEAP_CreateFreeBlock( subheap, (char *)(pArena + 1) + size,
-                              (pArena->size & ARENA_SIZE_MASK) - size );
-	/* assign size plus previous arena flags */
-        pArena->size = size | (pArena->size & ~ARENA_SIZE_MASK);
-    }
-    else
-    {
-        /* Turn off PREV_FREE flag in next block */
-        char *pNext = (char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK);
-        if (pNext < (char *)subheap + subheap->size)
-            *(DWORD *)pNext &= ~ARENA_FLAG_PREV_FREE;
-    }
-}
-
-/***********************************************************************
- *           HEAP_InitSubHeap
- */
-static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
-                                DWORD commitSize, DWORD totalSize )
-{
-    SUBHEAP *subheap = (SUBHEAP *)address;
-    WORD selector = 0;
-    FREE_LIST_ENTRY *pEntry;
-    int i;
-
-    /* Commit memory */
-
-    if (flags & HEAP_SHARED)
-        commitSize = totalSize;  /* always commit everything in a shared heap */
-    if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
-    {
-        WARN("Could not commit %08lx bytes for sub-heap %08lx\n",
-                   commitSize, (DWORD)address );
-        return FALSE;
-    }
-
-    /* Allocate a selector if needed */
-
-    if (flags & HEAP_WINE_SEGPTR)
-    {
-        unsigned char selflags = WINE_LDT_FLAGS_DATA;
-
-        if (flags & (HEAP_WINE_CODESEG | HEAP_WINE_CODE16SEG))
-            selflags = WINE_LDT_FLAGS_CODE;
-        if (flags & HEAP_WINE_CODESEG)
-            selflags |= WINE_LDT_FLAGS_32BIT;
-        selector = SELECTOR_AllocBlock( address, totalSize, selflags );
-        if (!selector)
-        {
-            ERR("Could not allocate selector\n" );
-            return FALSE;
-        }
-    }
-
-    /* Fill the sub-heap structure */
-
-    subheap->heap       = heap;
-    subheap->selector   = selector;
-    subheap->size       = totalSize;
-    subheap->commitSize = commitSize;
-    subheap->magic      = SUBHEAP_MAGIC;
-
-    if ( subheap != (SUBHEAP *)heap )
-    {
-        /* If this is a secondary subheap, insert it into list */
-
-        subheap->headerSize = sizeof(SUBHEAP);
-        subheap->next       = heap->subheap.next;
-        heap->subheap.next  = subheap;
-    }
-    else
-    {
-        /* If this is a primary subheap, initialize main heap */
-
-        subheap->headerSize = sizeof(HEAP);
-        subheap->next       = NULL;
-        heap->next          = NULL;
-        heap->flags         = flags;
-        heap->magic         = HEAP_MAGIC;
-
-        /* Build the free lists */
-
-        for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
-        {
-            pEntry->size           = HEAP_freeListSizes[i];
-            pEntry->arena.size     = 0 | ARENA_FLAG_FREE;
-            pEntry->arena.next     = i < HEAP_NB_FREE_LISTS-1 ?
-                         &heap->freeList[i+1].arena : &heap->freeList[0].arena;
-            pEntry->arena.prev     = i ? &heap->freeList[i-1].arena : 
-                                   &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
-            pEntry->arena.threadId = 0;
-            pEntry->arena.magic    = ARENA_FREE_MAGIC;
-        }
-
-        /* Initialize critical section */
-
-        InitializeCriticalSection( &heap->critSection );
-    }
-
-    /* Create the first free block */
-
-    HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize, 
-                          subheap->size - subheap->headerSize );
-
-    return TRUE;
-}
-
-/***********************************************************************
- *           HEAP_CreateSubHeap
- *
- * Create a sub-heap of the given size.
- * If heap == NULL, creates a main heap.
- */
-static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, DWORD flags, 
-                                    DWORD commitSize, DWORD totalSize )
-{
-    LPVOID address;
-
-    /* Round-up sizes on a 64K boundary */
-
-    if (flags & HEAP_WINE_SEGPTR)
-    {
-        totalSize = commitSize = 0x10000;  /* Only 64K at a time for SEGPTRs */
-    }
-    else
-    {
-        totalSize  = (totalSize + 0xffff) & 0xffff0000;
-        commitSize = (commitSize + 0xffff) & 0xffff0000;
-        if (!commitSize) commitSize = 0x10000;
-        if (totalSize < commitSize) totalSize = commitSize;
-    }
-
-    /* Allocate the memory block */
-
-    if (!(address = VirtualAlloc( NULL, totalSize,
-                                  MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
-    {
-        WARN("Could not VirtualAlloc %08lx bytes\n",
-                 totalSize );
-        return NULL;
-    }
-
-    /* Initialize subheap */
-
-    if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address, 
-                           address, flags, commitSize, totalSize ))
-    {
-        VirtualFree( address, 0, MEM_RELEASE );
-        return NULL;
-    }
-
-    return (SUBHEAP *)address;
-}
-
-
-/***********************************************************************
- *           HEAP_FindFreeBlock
- *
- * Find a free block at least as large as the requested size, and make sure
- * the requested size is committed.
- */
-static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, DWORD size,
-                                       SUBHEAP **ppSubHeap )
-{
-    SUBHEAP *subheap;
-    ARENA_FREE *pArena;
-    FREE_LIST_ENTRY *pEntry = heap->freeList;
-
-    /* Find a suitable free list, and in it find a block large enough */
-
-    while (pEntry->size < size) pEntry++;
-    pArena = pEntry->arena.next;
-    while (pArena != &heap->freeList[0].arena)
-    {
-        DWORD arena_size = (pArena->size & ARENA_SIZE_MASK) +
-                            sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
-        if (arena_size >= size)
-        {
-            subheap = HEAP_FindSubHeap( heap, pArena );
-            if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
-                                               + size + HEAP_MIN_BLOCK_SIZE))
-                return NULL;
-            *ppSubHeap = subheap;
-            return pArena;
-        }
-        pArena = pArena->next;
-    }
-
-    /* If no block was found, attempt to grow the heap */
-
-    if (!(heap->flags & HEAP_GROWABLE))
-    {
-        WARN("Not enough space in heap %08lx for %08lx bytes\n",
-                 (DWORD)heap, size );
-        return NULL;
-    }
-    /* make sure that we have a big enough size *committed* to fit another
-     * last free arena in !
-     * So just one heap struct, one first free arena which will eventually
-     * get inuse, and HEAP_MIN_BLOCK_SIZE for the second free arena that
-     * might get assigned all remaining free space in HEAP_ShrinkBlock() */
-    size += sizeof(SUBHEAP) + sizeof(ARENA_INUSE) + HEAP_MIN_BLOCK_SIZE;
-    if (!(subheap = HEAP_CreateSubHeap( heap, heap->flags, size,
-                                        max( HEAP_DEF_SIZE, size ) )))
-        return NULL;
-
-    TRACE("created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
-                (DWORD)subheap, size, (DWORD)heap );
-
-    *ppSubHeap = subheap;
-    return (ARENA_FREE *)(subheap + 1);
-}
-
-
-/***********************************************************************
- *           HEAP_IsValidArenaPtr
- *
- * Check that the pointer is inside the range possible for arenas.
- */
-static BOOL HEAP_IsValidArenaPtr( HEAP *heap, void *ptr )
-{
-    int i;
-    SUBHEAP *subheap = HEAP_FindSubHeap( heap, ptr );
-    if (!subheap) return FALSE;
-    if ((char *)ptr >= (char *)subheap + subheap->headerSize) return TRUE;
-    if (subheap != &heap->subheap) return FALSE;
-    for (i = 0; i < HEAP_NB_FREE_LISTS; i++)
-        if (ptr == (void *)&heap->freeList[i].arena) return TRUE;
-    return FALSE;
-}
-
-
-/***********************************************************************
- *           HEAP_ValidateFreeArena
- */
-static BOOL HEAP_ValidateFreeArena( SUBHEAP *subheap, ARENA_FREE *pArena )
-{
-    char *heapEnd = (char *)subheap + subheap->size;
-
-#if !defined(ALLOW_UNALIGNED_ACCESS)
-    /* Check for unaligned pointers */
-    if ( (long)pArena % sizeof(void *) != 0 )
-    {
-        ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
-             (DWORD)subheap->heap, (DWORD)pArena );
-        return FALSE;
-    }
-#endif
-
-    /* Check magic number */
-    if (pArena->magic != ARENA_FREE_MAGIC)
-    {
-        ERR("Heap %08lx: invalid free arena magic for %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check size flags */
-    if (!(pArena->size & ARENA_FLAG_FREE) ||
-        (pArena->size & ARENA_FLAG_PREV_FREE))
-    {
-        ERR("Heap %08lx: bad flags %lx for free arena %08lx\n",
-                 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
-    }
-    /* Check arena size */
-    if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
-    {
-        ERR("Heap %08lx: bad size %08lx for free arena %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check that next pointer is valid */
-    if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->next ))
-    {
-        ERR("Heap %08lx: bad next ptr %08lx for arena %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check that next arena is free */
-    if (!(pArena->next->size & ARENA_FLAG_FREE) ||
-        (pArena->next->magic != ARENA_FREE_MAGIC))
-    { 
-        ERR("Heap %08lx: next arena %08lx invalid for %08lx\n", 
-                 (DWORD)subheap->heap, (DWORD)pArena->next, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check that prev pointer is valid */
-    if (!HEAP_IsValidArenaPtr( subheap->heap, pArena->prev ))
-    {
-        ERR("Heap %08lx: bad prev ptr %08lx for arena %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check that prev arena is free */
-    if (!(pArena->prev->size & ARENA_FLAG_FREE) ||
-        (pArena->prev->magic != ARENA_FREE_MAGIC))
-    { 
-	/* this often means that the prev arena got overwritten
-	 * by a memory write before that prev arena */
-        ERR("Heap %08lx: prev arena %08lx invalid for %08lx\n", 
-                 (DWORD)subheap->heap, (DWORD)pArena->prev, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check that next block has PREV_FREE flag */
-    if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd)
-    {
-        if (!(*(DWORD *)((char *)(pArena + 1) +
-            (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
-        {
-            ERR("Heap %08lx: free arena %08lx next block has no PREV_FREE flag\n",
-                     (DWORD)subheap->heap, (DWORD)pArena );
-            return FALSE;
-        }
-        /* Check next block back pointer */
-        if (*((ARENA_FREE **)((char *)(pArena + 1) +
-            (pArena->size & ARENA_SIZE_MASK)) - 1) != pArena)
-        {
-            ERR("Heap %08lx: arena %08lx has wrong back ptr %08lx\n",
-                     (DWORD)subheap->heap, (DWORD)pArena,
-                     *((DWORD *)((char *)(pArena+1)+ (pArena->size & ARENA_SIZE_MASK)) - 1));
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HEAP_ValidateInUseArena
- */
-static BOOL HEAP_ValidateInUseArena( SUBHEAP *subheap, ARENA_INUSE *pArena, BOOL quiet )
-{
-    char *heapEnd = (char *)subheap + subheap->size;
-
-#if !defined(ALLOW_UNALIGNED_ACCESS)
-    /* Check for unaligned pointers */
-    if ( (long)pArena % sizeof(void *) != 0 )
-    {
-        if ( quiet == NOISY )
-        {
-            ERR( "Heap %08lx: unaligned arena pointer %08lx\n",
-                  (DWORD)subheap->heap, (DWORD)pArena );
-            if ( TRACE_ON(heap) )
-                HEAP_Dump( subheap->heap );
-        }
-        else if ( WARN_ON(heap) )
-        {
-            WARN( "Heap %08lx: unaligned arena pointer %08lx\n",
-                  (DWORD)subheap->heap, (DWORD)pArena );
-            if ( TRACE_ON(heap) )
-                HEAP_Dump( subheap->heap );
-        }
-        return FALSE;
-    }
-#endif
-
-    /* Check magic number */
-    if (pArena->magic != ARENA_INUSE_MAGIC)
-    {
-        if (quiet == NOISY) {
-        ERR("Heap %08lx: invalid in-use arena magic for %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena );
-            if (TRACE_ON(heap))
-               HEAP_Dump( subheap->heap );
-        }  else if (WARN_ON(heap)) {
-            WARN("Heap %08lx: invalid in-use arena magic for %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena );
-            if (TRACE_ON(heap))
-               HEAP_Dump( subheap->heap );
-        }
-        return FALSE;
-    }
-    /* Check size flags */
-    if (pArena->size & ARENA_FLAG_FREE) 
-    {
-        ERR("Heap %08lx: bad flags %lx for in-use arena %08lx\n",
-                 (DWORD)subheap->heap, pArena->size & ~ARENA_SIZE_MASK, (DWORD)pArena );
-    }
-    /* Check arena size */
-    if ((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) > heapEnd)
-    {
-        ERR("Heap %08lx: bad size %08lx for in-use arena %08lx\n",
-                 (DWORD)subheap->heap, (DWORD)pArena->size & ARENA_SIZE_MASK, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check next arena PREV_FREE flag */
-    if (((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK) < heapEnd) &&
-        (*(DWORD *)((char *)(pArena + 1) + (pArena->size & ARENA_SIZE_MASK)) & ARENA_FLAG_PREV_FREE))
-    {
-        ERR("Heap %08lx: in-use arena %08lx next block has PREV_FREE flag\n",
-                 (DWORD)subheap->heap, (DWORD)pArena );
-        return FALSE;
-    }
-    /* Check prev free arena */
-    if (pArena->size & ARENA_FLAG_PREV_FREE)
-    {
-        ARENA_FREE *pPrev = *((ARENA_FREE **)pArena - 1);
-        /* Check prev pointer */
-        if (!HEAP_IsValidArenaPtr( subheap->heap, pPrev ))
-        {
-            ERR("Heap %08lx: bad back ptr %08lx for arena %08lx\n",
-                    (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
-            return FALSE;
-        }
-        /* Check that prev arena is free */
-        if (!(pPrev->size & ARENA_FLAG_FREE) ||
-            (pPrev->magic != ARENA_FREE_MAGIC))
-        { 
-            ERR("Heap %08lx: prev arena %08lx invalid for in-use %08lx\n", 
-                     (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
-            return FALSE;
-        }
-        /* Check that prev arena is really the previous block */
-        if ((char *)(pPrev + 1) + (pPrev->size & ARENA_SIZE_MASK) != (char *)pArena)
-        {
-            ERR("Heap %08lx: prev arena %08lx is not prev for in-use %08lx\n",
-                     (DWORD)subheap->heap, (DWORD)pPrev, (DWORD)pArena );
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HEAP_GetSegptr
- *
- * Transform a linear pointer into a SEGPTR. The pointer must have been
- * allocated from a HEAP_WINE_SEGPTR heap.
- */
-SEGPTR HEAP_GetSegptr( HANDLE heap, DWORD flags, LPCVOID ptr )
-{
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-    SUBHEAP *subheap;
-    SEGPTR ret = 0;
-
-    /* Validate the parameters */
-
-    if (!heapPtr) return 0;
-    flags |= heapPtr->flags;
-    if (!(flags & HEAP_WINE_SEGPTR))
-    {
-        ERR("Heap %08x is not a SEGPTR heap\n",
-                 heap );
-        return 0;
-    }
-    if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-
-    /* Get the subheap */
-
-    if ((subheap = HEAP_FindSubHeap( heapPtr, ptr )))
-        ret = MAKESEGPTR(subheap->selector, (char *)ptr - (char *)subheap);
-
-    if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-    return ret;
-}
-
-/***********************************************************************
- *           MapLS   (KERNEL32.@)
- *           MapLS   (KERNEL.358)
- *
- * Maps linear pointer to segmented.
- */
-SEGPTR WINAPI MapLS( LPCVOID ptr )
-{
-    SUBHEAP *subheap;
-    SEGPTR ret = 0;
-
-    if (!HIWORD(ptr)) return (SEGPTR)ptr;
-
-    /* check if the pointer is inside the segptr heap */
-    EnterCriticalSection( &segptrHeap->critSection );
-    if ((subheap = HEAP_FindSubHeap( segptrHeap, ptr )))
-        ret = MAKESEGPTR( subheap->selector, (char *)ptr - (char *)subheap );
-    LeaveCriticalSection( &segptrHeap->critSection );
-
-    /* otherwise, allocate a brand-new selector */
-    if (!ret)
-    {
-        WORD sel = SELECTOR_AllocBlock( ptr, 0x10000, WINE_LDT_FLAGS_DATA );
-        ret = MAKESEGPTR( sel, 0 );
-    }
-    return ret;
-}
-
-
-/***********************************************************************
- *           UnMapLS   (KERNEL32.@)
- *           UnMapLS   (KERNEL.359)
- *
- * Free mapped selector.
- */
-void WINAPI UnMapLS( SEGPTR sptr )
-{
-    SUBHEAP *subheap;
-    if (!SELECTOROF(sptr)) return;
-
-    /* check if ptr is inside segptr heap */
-    EnterCriticalSection( &segptrHeap->critSection );
-    subheap = HEAP_FindSubHeap( segptrHeap, MapSL(sptr) );
-    if ((subheap) && (subheap->selector != SELECTOROF(sptr))) subheap = NULL;
-    LeaveCriticalSection( &segptrHeap->critSection );
-    /* if not inside heap, free the selector */
-    if (!subheap) FreeSelector16( SELECTOROF(sptr) );
-}
-
-/***********************************************************************
- *           HEAP_IsRealArena  [Internal]
- * Validates a block is a valid arena.
- *
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-static BOOL HEAP_IsRealArena( HEAP *heapPtr,   /* [in] ptr to the heap */
-              DWORD flags,   /* [in] Bit flags that control access during operation */
-              LPCVOID block, /* [in] Optional pointer to memory block to validate */
-              BOOL quiet )   /* [in] Flag - if true, HEAP_ValidateInUseArena
-                              *             does not complain    */
-{
-    SUBHEAP *subheap;
-    BOOL ret = TRUE;
-
-    if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
-    {
-        ERR("Invalid heap %p!\n", heapPtr );
-        return FALSE;
-    }
-
-    flags &= HEAP_NO_SERIALIZE;
-    flags |= heapPtr->flags;
-    /* calling HeapLock may result in infinite recursion, so do the critsect directly */
-    if (!(flags & HEAP_NO_SERIALIZE))
-        EnterCriticalSection( &heapPtr->critSection );
-
-    if (block)
-    {
-        /* Only check this single memory block */
-
-        if (!(subheap = HEAP_FindSubHeap( heapPtr, block )) ||
-            ((char *)block < (char *)subheap + subheap->headerSize
-                              + sizeof(ARENA_INUSE)))
-        {
-            if (quiet == NOISY) 
-                ERR("Heap %p: block %p is not inside heap\n", heapPtr, block );
-            else if (WARN_ON(heap)) 
-                WARN("Heap %p: block %p is not inside heap\n", heapPtr, block );
-            ret = FALSE;
-        } else
-            ret = HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)block - 1, quiet );
-
-        if (!(flags & HEAP_NO_SERIALIZE))
-            LeaveCriticalSection( &heapPtr->critSection );
-        return ret;
-    }
-
-    subheap = &heapPtr->subheap;
-    while (subheap && ret)
-    {
-        char *ptr = (char *)subheap + subheap->headerSize;
-        while (ptr < (char *)subheap + subheap->size)
-        {
-            if (*(DWORD *)ptr & ARENA_FLAG_FREE)
-            {
-                if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) {
-                    ret = FALSE;
-                    break;
-                }
-                ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
-            }
-            else
-            {
-                if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) {
-                    ret = FALSE;
-                    break;
-                }
-                ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK);
-            }
-        }
-        subheap = subheap->next;
-    }
-
-    if (!(flags & HEAP_NO_SERIALIZE))
-	LeaveCriticalSection( &heapPtr->critSection );
-    return ret;
-}
-
-
-/***********************************************************************
- *           HEAP_CreateSystemHeap
- *
- * Create the system heap.
- */
-static HANDLE HEAP_CreateSystemHeap(void)
-{
-    int created;
-
-    HANDLE map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
-                                     0, HEAP_DEF_SIZE, "__SystemHeap" );
-    if (!map) return 0;
-    created = (GetLastError() != ERROR_ALREADY_EXISTS);
-
-    if (!(systemHeap = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
-    {
-        /* pre-defined address not available, use any one */
-        ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
-        return 0;
-    }
-
-    if (created)  /* newly created heap */
-    {
-        HEAP_InitSubHeap( systemHeap, systemHeap, HEAP_SHARED, 0, HEAP_DEF_SIZE );
-        MakeCriticalSectionGlobal( &systemHeap->critSection );
-    }
-    else
-    {
-        /* wait for the heap to be initialized */
-        while (!systemHeap->critSection.LockSemaphore) Sleep(1);
-    }
-    CloseHandle( map );
-    return (HANDLE)systemHeap;
-}
-
-
-/***********************************************************************
- *           HeapCreate   (KERNEL32.@)
- * RETURNS
- *	Handle of heap: Success
- *	NULL: Failure
- */
-HANDLE WINAPI HeapCreate(
-                DWORD flags,       /* [in] Heap allocation flag */
-                DWORD initialSize, /* [in] Initial heap size */
-                DWORD maxSize      /* [in] Maximum heap size */
-) {
-    SUBHEAP *subheap;
-
-    if ( flags & HEAP_SHARED ) {
-        if (!systemHeap) HEAP_CreateSystemHeap();
-        else WARN( "Shared Heap requested, returning system heap.\n" );
-        return (HANDLE)systemHeap;
-    }
-
-    /* Allocate the heap block */
-
-    if (!maxSize)
-    {
-        maxSize = HEAP_DEF_SIZE;
-        flags |= HEAP_GROWABLE;
-    }
-    if (!(subheap = HEAP_CreateSubHeap( NULL, flags, initialSize, maxSize )))
-    {
-        SetLastError( ERROR_OUTOFMEMORY );
-        return 0;
-    }
-
-    /* link it into the per-process heap list */
-    if (processHeap)
-    {
-        HEAP *heapPtr = subheap->heap;
-        EnterCriticalSection( &processHeap->critSection );
-        heapPtr->next = firstHeap;
-        firstHeap = heapPtr;
-        LeaveCriticalSection( &processHeap->critSection );
-    }
-    else  /* assume the first heap we create is the process main heap */
-    {
-        SUBHEAP *segptr;
-        processHeap = subheap->heap;
-        /* create the SEGPTR heap */
-        if (!(segptr = HEAP_CreateSubHeap( NULL, flags|HEAP_WINE_SEGPTR|HEAP_GROWABLE, 0, 0 )))
-        {
-            SetLastError( ERROR_OUTOFMEMORY );
-            return 0;
-        }
-        segptrHeap = segptr->heap;
-    }
-    return (HANDLE)subheap;
-}
-
-/***********************************************************************
- *           HeapDestroy   (KERNEL32.@)
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
-{
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-    SUBHEAP *subheap;
-
-    TRACE("%08x\n", heap );
-    if (!heapPtr) return FALSE;
-
-    if (heapPtr == systemHeap)
-    {
-        WARN( "attempt to destroy system heap, returning TRUE!\n" );
-        return TRUE;
-    }
-    if (heapPtr == processHeap)  /* cannot delete the main process heap */
-    {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return FALSE;
-    }
-    else /* remove it from the per-process list */
-    {
-        HEAP **pptr;
-        EnterCriticalSection( &processHeap->critSection );
-        pptr = &firstHeap;
-        while (*pptr && *pptr != heapPtr) pptr = &(*pptr)->next;
-        if (*pptr) *pptr = (*pptr)->next;
-        LeaveCriticalSection( &processHeap->critSection );
-    }
-
-    DeleteCriticalSection( &heapPtr->critSection );
-    subheap = &heapPtr->subheap;
-    while (subheap)
-    {
-        SUBHEAP *next = subheap->next;
-        if (subheap->selector) FreeSelector16( subheap->selector );
-        VirtualFree( subheap, 0, MEM_RELEASE );
-        subheap = next;
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HeapAlloc   (KERNEL32.@)
- * RETURNS
- *	Pointer to allocated memory block
- *	NULL: Failure
- */
-LPVOID WINAPI HeapAlloc(
-              HANDLE heap, /* [in] Handle of private heap block */
-              DWORD flags,   /* [in] Heap allocation control flags */
-              DWORD size     /* [in] Number of bytes to allocate */
-) {
-    ARENA_FREE *pArena;
-    ARENA_INUSE *pInUse;
-    SUBHEAP *subheap;
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-
-    /* Validate the parameters */
-
-    if ((flags & HEAP_WINE_SEGPTR) && size < 0x10000) heapPtr = segptrHeap;
-    if (!heapPtr) return NULL;
-    flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY;
-    flags |= heapPtr->flags;
-    size = (size + 3) & ~3;
-    if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
-
-    if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-    /* Locate a suitable free block */
-
-    if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
-    {
-        TRACE("(%08x,%08lx,%08lx): returning NULL\n",
-                  heap, flags, size  );
-        if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-        SetLastError( ERROR_COMMITMENT_LIMIT );
-        return NULL;
-    }
-
-    /* Remove the arena from the free list */
-
-    pArena->next->prev = pArena->prev;
-    pArena->prev->next = pArena->next;
-
-    /* Build the in-use arena */
-
-    pInUse = (ARENA_INUSE *)pArena;
-
-    /* in-use arena is smaller than free arena,
-     * so we have to add the difference to the size */
-    pInUse->size      = (pInUse->size & ~ARENA_FLAG_FREE)
-                        + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
-    pInUse->callerEIP = GET_EIP();
-    pInUse->threadId  = GetCurrentTask();
-    pInUse->magic     = ARENA_INUSE_MAGIC;
-
-    /* Shrink the block */
-
-    HEAP_ShrinkBlock( subheap, pInUse, size );
-
-    if (flags & HEAP_ZERO_MEMORY)
-        memset( pInUse + 1, 0, pInUse->size & ARENA_SIZE_MASK );
-    else if (TRACE_ON(heap))
-        memset( pInUse + 1, ARENA_INUSE_FILLER, pInUse->size & ARENA_SIZE_MASK );
-
-    if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
-    TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
-                  heap, flags, size, (DWORD)(pInUse + 1) );
-    return (LPVOID)(pInUse + 1);
-}
-
-
-/***********************************************************************
- *           HeapFree   (KERNEL32.@)
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-BOOL WINAPI HeapFree(
-              HANDLE heap, /* [in] Handle of heap */
-              DWORD flags,   /* [in] Heap freeing flags */
-              LPVOID ptr     /* [in] Address of memory to free */
-) {
-    ARENA_INUSE *pInUse;
-    SUBHEAP *subheap;
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-
-    /* Validate the parameters */
-
-    if (!ptr) return TRUE;  /* freeing a NULL ptr isn't an error in Win2k */
-    if (flags & HEAP_WINE_SEGPTR) heapPtr = segptrHeap;
-    if (!heapPtr) return FALSE;
-
-    flags &= HEAP_NO_SERIALIZE;
-    flags |= heapPtr->flags;
-    if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-    if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
-    {
-        if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-        SetLastError( ERROR_INVALID_PARAMETER );
-        TRACE("(%08x,%08lx,%08lx): returning FALSE\n",
-                      heap, flags, (DWORD)ptr );
-        return FALSE;
-    }
-
-    /* Turn the block into a free block */
-
-    pInUse  = (ARENA_INUSE *)ptr - 1;
-    subheap = HEAP_FindSubHeap( heapPtr, pInUse );
-    HEAP_MakeInUseBlockFree( subheap, pInUse );
-
-    if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
-    TRACE("(%08x,%08lx,%08lx): returning TRUE\n",
-                  heap, flags, (DWORD)ptr );
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HeapReAlloc   (KERNEL32.@)
- * RETURNS
- *	Pointer to reallocated memory block
- *	NULL: Failure
- */
-LPVOID WINAPI HeapReAlloc(
-              HANDLE heap, /* [in] Handle of heap block */
-              DWORD flags,   /* [in] Heap reallocation flags */
-              LPVOID ptr,    /* [in] Address of memory to reallocate */
-              DWORD size     /* [in] Number of bytes to reallocate */
-) {
-    ARENA_INUSE *pArena;
-    DWORD oldSize;
-    HEAP *heapPtr;
-    SUBHEAP *subheap;
-
-    if (!ptr) return HeapAlloc( heap, flags, size );  /* FIXME: correct? */
-    if ((flags & HEAP_WINE_SEGPTR) && size < 0x10000) heapPtr = segptrHeap;
-    if (!(heapPtr = HEAP_GetPtr( heap ))) return FALSE;
-
-    /* Validate the parameters */
-
-    flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY |
-             HEAP_REALLOC_IN_PLACE_ONLY;
-    flags |= heapPtr->flags;
-    size = (size + 3) & ~3;
-    if (size < HEAP_MIN_BLOCK_SIZE) size = HEAP_MIN_BLOCK_SIZE;
-
-    if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-    if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
-    {
-        if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-        SetLastError( ERROR_INVALID_PARAMETER );
-        TRACE("(%08x,%08lx,%08lx,%08lx): returning NULL\n",
-                      heap, flags, (DWORD)ptr, size );
-        return NULL;
-    }
-
-    /* Check if we need to grow the block */
-
-    pArena = (ARENA_INUSE *)ptr - 1;
-    pArena->threadId = GetCurrentTask();
-    subheap = HEAP_FindSubHeap( heapPtr, pArena );
-    oldSize = (pArena->size & ARENA_SIZE_MASK);
-    if (size > oldSize)
-    {
-        char *pNext = (char *)(pArena + 1) + oldSize;
-        if ((pNext < (char *)subheap + subheap->size) &&
-            (*(DWORD *)pNext & ARENA_FLAG_FREE) &&
-            (oldSize + (*(DWORD *)pNext & ARENA_SIZE_MASK) + sizeof(ARENA_FREE) >= size))
-        {
-            /* The next block is free and large enough */
-            ARENA_FREE *pFree = (ARENA_FREE *)pNext;
-            pFree->next->prev = pFree->prev;
-            pFree->prev->next = pFree->next;
-            pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
-            if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
-                                               + size + HEAP_MIN_BLOCK_SIZE))
-            {
-                if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-                SetLastError( ERROR_OUTOFMEMORY );
-                return NULL;
-            }
-            HEAP_ShrinkBlock( subheap, pArena, size );
-        }
-        else  /* Do it the hard way */
-        {
-            ARENA_FREE *pNew;
-            ARENA_INUSE *pInUse;
-            SUBHEAP *newsubheap;
-
-            if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) ||
-                !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
-            {
-                if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-                SetLastError( ERROR_OUTOFMEMORY );
-                return NULL;
-            }
-
-            /* Build the in-use arena */
-
-            pNew->next->prev = pNew->prev;
-            pNew->prev->next = pNew->next;
-            pInUse = (ARENA_INUSE *)pNew;
-            pInUse->size     = (pInUse->size & ~ARENA_FLAG_FREE)
-                               + sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
-            pInUse->threadId = GetCurrentTask();
-            pInUse->magic    = ARENA_INUSE_MAGIC;
-            HEAP_ShrinkBlock( newsubheap, pInUse, size );
-            memcpy( pInUse + 1, pArena + 1, oldSize );
-
-            /* Free the previous block */
-
-            HEAP_MakeInUseBlockFree( subheap, pArena );
-            subheap = newsubheap;
-            pArena  = pInUse;
-        }
-    }
-    else HEAP_ShrinkBlock( subheap, pArena, size );  /* Shrink the block */
-
-    /* Clear the extra bytes if needed */
-
-    if (size > oldSize)
-    {
-        if (flags & HEAP_ZERO_MEMORY)
-            memset( (char *)(pArena + 1) + oldSize, 0,
-                    (pArena->size & ARENA_SIZE_MASK) - oldSize );
-        else if (TRACE_ON(heap))
-            memset( (char *)(pArena + 1) + oldSize, ARENA_INUSE_FILLER,
-                    (pArena->size & ARENA_SIZE_MASK) - oldSize );
-    }
-
-    /* Return the new arena */
-
-    pArena->callerEIP = GET_EIP();
-    if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
-    TRACE("(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
-                  heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
-    return (LPVOID)(pArena + 1);
-}
-
-
-/***********************************************************************
- *           HeapCompact   (KERNEL32.@)
- */
-DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
-{
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
-}
-
-
-/***********************************************************************
- *           HeapLock   (KERNEL32.@)
- * Attempts to acquire the critical section object for a specified heap.
- *
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-BOOL WINAPI HeapLock(
-              HANDLE heap /* [in] Handle of heap to lock for exclusive access */
-) {
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-    if (!heapPtr) return FALSE;
-    EnterCriticalSection( &heapPtr->critSection );
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HeapUnlock   (KERNEL32.@)
- * Releases ownership of the critical section object.
- *
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-BOOL WINAPI HeapUnlock(
-              HANDLE heap /* [in] Handle to the heap to unlock */
-) {
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-    if (!heapPtr) return FALSE;
-    LeaveCriticalSection( &heapPtr->critSection );
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           HeapSize   (KERNEL32.@)
- * RETURNS
- *	Size in bytes of allocated memory
- *	0xffffffff: Failure
- */
-DWORD WINAPI HeapSize(
-             HANDLE heap, /* [in] Handle of heap */
-             DWORD flags,   /* [in] Heap size control flags */
-             LPVOID ptr     /* [in] Address of memory to return size for */
-) {
-    DWORD ret;
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-
-    if (flags & HEAP_WINE_SEGPTR) heapPtr = segptrHeap;
-    if (!heapPtr) return FALSE;
-    flags &= HEAP_NO_SERIALIZE;
-    flags |= heapPtr->flags;
-    if (!(flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-    if (!HEAP_IsRealArena( heapPtr, HEAP_NO_SERIALIZE, ptr, QUIET ))
-    {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        ret = 0xffffffff;
-    }
-    else
-    {
-        ARENA_INUSE *pArena = (ARENA_INUSE *)ptr - 1;
-        ret = pArena->size & ARENA_SIZE_MASK;
-    }
-    if (!(flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
-    TRACE("(%08x,%08lx,%08lx): returning %08lx\n",
-                  heap, flags, (DWORD)ptr, ret );
-    return ret;
-}
-
-
-/***********************************************************************
- *           HeapValidate   (KERNEL32.@)
- * Validates a specified heap.
- *
- * NOTES
- *	Flags is ignored.
- *
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-BOOL WINAPI HeapValidate(
-              HANDLE heap, /* [in] Handle to the heap */
-              DWORD flags,   /* [in] Bit flags that control access during operation */
-              LPCVOID block  /* [in] Optional pointer to memory block to validate */
-) {
-    HEAP *heapPtr = HEAP_GetPtr( heap );
-    if (flags & HEAP_WINE_SEGPTR) heapPtr = segptrHeap;
-    if (!heapPtr) return FALSE;
-    return HEAP_IsRealArena( heapPtr, flags, block, QUIET );
-}
-
-
-/***********************************************************************
- *           HeapWalk   (KERNEL32.@)
- * Enumerates the memory blocks in a specified heap.
- * See HEAP_Dump() for info on heap structure.
- *
- * TODO
- *   - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
- *     PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
- *
- * RETURNS
- *	TRUE: Success
- *	FALSE: Failure
- */
-BOOL WINAPI HeapWalk(
-              HANDLE heap,               /* [in]  Handle to heap to enumerate */
-              LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
-) {
-    HEAP *heapPtr = HEAP_GetPtr(heap);
-    SUBHEAP *sub, *currentheap = NULL;
-    BOOL ret = FALSE;
-    char *ptr;
-    int region_index = 0;
-
-    if (!heapPtr || !entry)
-    {
-	SetLastError(ERROR_INVALID_PARAMETER);
-	return FALSE;
-    }
-
-    if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) EnterCriticalSection( &heapPtr->critSection );
-
-    /* set ptr to the next arena to be examined */
-
-    if (!entry->lpData) /* first call (init) ? */
-    {
-	TRACE("begin walking of heap 0x%08x.\n", heap);
-	/*HEAP_Dump(heapPtr);*/
-	currentheap = &heapPtr->subheap;
-	ptr = (char*)currentheap + currentheap->headerSize;
-    }
-    else
-    {
-	ptr = entry->lpData;
-	sub = &heapPtr->subheap;
-	while (sub)
-	{
-	    if (((char *)ptr >= (char *)sub) &&
-		((char *)ptr < (char *)sub + sub->size))
-	    {
-		currentheap = sub;
-		break;
-	    }
-	    sub = sub->next;
-	    region_index++;
-	}
-	if (currentheap == NULL)
-	{
-	    ERR("no matching subheap found, shouldn't happen !\n");
-	    SetLastError(ERROR_NO_MORE_ITEMS);
-	    goto HW_end;
-	}
-
-	ptr += entry->cbData; /* point to next arena */
-	if (ptr > (char *)currentheap + currentheap->size - 1)
-	{   /* proceed with next subheap */
-	    if (!(currentheap = currentheap->next))
-	    {  /* successfully finished */
-		TRACE("end reached.\n");
-		SetLastError(ERROR_NO_MORE_ITEMS);
-		goto HW_end;
-	    }
-	    ptr = (char*)currentheap + currentheap->headerSize;
-	}
-    }
-
-    entry->wFlags = 0;
-    if (*(DWORD *)ptr & ARENA_FLAG_FREE)
-    {
-	ARENA_FREE *pArena = (ARENA_FREE *)ptr;
-
-	/*TRACE("free, magic: %04x\n", pArena->magic);*/
-
-	entry->lpData = pArena + 1;
-	entry->cbData = pArena->size & ARENA_SIZE_MASK;
-	entry->cbOverhead = sizeof(ARENA_FREE);
-	entry->wFlags = PROCESS_HEAP_UNCOMMITTED_RANGE;
-    }
-    else
-    {
-	ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
-
-	/*TRACE("busy, magic: %04x\n", pArena->magic);*/
-	
-	entry->lpData = pArena + 1;
-	entry->cbData = pArena->size & ARENA_SIZE_MASK;
-	entry->cbOverhead = sizeof(ARENA_INUSE);
-	entry->wFlags = PROCESS_HEAP_ENTRY_BUSY;
-	/* FIXME: can't handle PROCESS_HEAP_ENTRY_MOVEABLE
-	and PROCESS_HEAP_ENTRY_DDESHARE yet */
-    }
-
-    entry->iRegionIndex = region_index;
-
-    /* first element of heap ? */
-    if (ptr == (char *)(currentheap + currentheap->headerSize))
-    {
-	entry->wFlags |= PROCESS_HEAP_REGION;
-	entry->u.Region.dwCommittedSize = currentheap->commitSize;
-	entry->u.Region.dwUnCommittedSize =
-		currentheap->size - currentheap->commitSize;
-	entry->u.Region.lpFirstBlock = /* first valid block */
-		currentheap + currentheap->headerSize;
-	entry->u.Region.lpLastBlock  = /* first invalid block */
-		currentheap + currentheap->size;
-    }
-    ret = TRUE;
-
-HW_end:
-    if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) LeaveCriticalSection( &heapPtr->critSection );
-
-    return ret;
-}
-
-
-/***********************************************************************
- *           GetProcessHeap    (KERNEL32.@)
- */
-HANDLE WINAPI GetProcessHeap(void)
-{
-    return (HANDLE)processHeap;
-}
-
-
-/***********************************************************************
- *           GetProcessHeaps    (KERNEL32.@)
- */
-DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
-{
-    DWORD total;
-    HEAP *ptr;
-
-    if (!processHeap) return 0;  /* should never happen */
-    total = 1;  /* main heap */
-    EnterCriticalSection( &processHeap->critSection );
-    for (ptr = firstHeap; ptr; ptr = ptr->next) total++;
-    if (total <= count)
-    {
-        *heaps++ = (HANDLE)processHeap;
-        for (ptr = firstHeap; ptr; ptr = ptr->next) *heaps++ = (HANDLE)ptr;
-    }
-    LeaveCriticalSection( &processHeap->critSection );
-    return total;
-}
-
+#define SYSTEM_HEAP_SIZE  0x100000   /* Default heap size = 1Mb */
 
-/***********************************************************************
- * 32-bit local heap functions (Win95; undocumented)
- */
 
 #define HTABLE_SIZE      0x10000
 #define HTABLE_PAGESIZE  0x1000
@@ -1704,6 +60,208 @@
 
 #define LOCAL32_MAGIC    ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
 
+static HANDLE systemHeap;   /* globally shared heap */
+
+/***********************************************************************
+ *           HEAP_CreateSystemHeap
+ *
+ * Create the system heap.
+ */
+inline static HANDLE HEAP_CreateSystemHeap(void)
+{
+    int created;
+    void *base;
+    HANDLE map, event;
+    UNICODE_STRING event_name;
+    OBJECT_ATTRIBUTES event_attr;
+
+    if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
+                                    0, SYSTEM_HEAP_SIZE, "__SystemHeap" ))) return 0;
+    created = (GetLastError() != ERROR_ALREADY_EXISTS);
+
+    if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
+    {
+        /* pre-defined address not available */
+        ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
+        return 0;
+    }
+
+    /* create the system heap event */
+    RtlCreateUnicodeStringFromAsciiz( &event_name, "__SystemHeapEvent" );
+    event_attr.Length = sizeof(event_attr);
+    event_attr.RootDirectory = 0;
+    event_attr.ObjectName = &event_name;
+    event_attr.Attributes = 0;
+    event_attr.SecurityDescriptor = NULL;
+    event_attr.SecurityQualityOfService = NULL;
+    NtCreateEvent( &event, EVENT_ALL_ACCESS, &event_attr, TRUE, FALSE );
+
+    if (created)  /* newly created heap */
+    {
+        systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
+                                    SYSTEM_HEAP_SIZE, NULL, NULL );
+        NtSetEvent( event, NULL );
+    }
+    else
+    {
+        /* wait for the heap to be initialized */
+        WaitForSingleObject( event, INFINITE );
+    }
+    CloseHandle( map );
+    return systemHeap;
+}
+
+
+/***********************************************************************
+ *           HeapCreate   (KERNEL32.@)
+ * RETURNS
+ *	Handle of heap: Success
+ *	NULL: Failure
+ */
+HANDLE WINAPI HeapCreate(
+                DWORD flags,       /* [in] Heap allocation flag */
+                DWORD initialSize, /* [in] Initial heap size */
+                DWORD maxSize      /* [in] Maximum heap size */
+) {
+    HANDLE ret;
+
+    if ( flags & HEAP_SHARED )
+    {
+        if (!systemHeap) HEAP_CreateSystemHeap();
+        else WARN( "Shared Heap requested, returning system heap.\n" );
+        ret = systemHeap;
+    }
+    else
+    {
+        ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
+        if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *           HeapDestroy   (KERNEL32.@)
+ * RETURNS
+ *	TRUE: Success
+ *	FALSE: Failure
+ */
+BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
+{
+    if (heap == systemHeap)
+    {
+        WARN( "attempt to destroy system heap, returning TRUE!\n" );
+        return TRUE;
+    }
+    if (!RtlDestroyHeap( heap )) return TRUE;
+    SetLastError( ERROR_INVALID_HANDLE );
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           HeapCompact   (KERNEL32.@)
+ */
+DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
+{
+    return RtlCompactHeap( heap, flags );
+}
+
+
+/***********************************************************************
+ *           HeapLock   (KERNEL32.@)
+ * Attempts to acquire the critical section object for a specified heap.
+ *
+ * RETURNS
+ *	TRUE: Success
+ *	FALSE: Failure
+ */
+BOOL WINAPI HeapLock(
+              HANDLE heap /* [in] Handle of heap to lock for exclusive access */
+) {
+    return RtlLockHeap( heap );
+}
+
+
+/***********************************************************************
+ *           HeapUnlock   (KERNEL32.@)
+ * Releases ownership of the critical section object.
+ *
+ * RETURNS
+ *	TRUE: Success
+ *	FALSE: Failure
+ */
+BOOL WINAPI HeapUnlock(
+              HANDLE heap /* [in] Handle to the heap to unlock */
+) {
+    return RtlUnlockHeap( heap );
+}
+
+
+/***********************************************************************
+ *           HeapValidate   (KERNEL32.@)
+ * Validates a specified heap.
+ *
+ * NOTES
+ *	Flags is ignored.
+ *
+ * RETURNS
+ *	TRUE: Success
+ *	FALSE: Failure
+ */
+BOOL WINAPI HeapValidate(
+              HANDLE heap, /* [in] Handle to the heap */
+              DWORD flags,   /* [in] Bit flags that control access during operation */
+              LPCVOID block  /* [in] Optional pointer to memory block to validate */
+) {
+    return RtlValidateHeap( heap, flags, block );
+}
+
+
+/***********************************************************************
+ *           HeapWalk   (KERNEL32.@)
+ * Enumerates the memory blocks in a specified heap.
+ *
+ * TODO
+ *   - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
+ *     PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
+ *
+ * RETURNS
+ *	TRUE: Success
+ *	FALSE: Failure
+ */
+BOOL WINAPI HeapWalk(
+              HANDLE heap,               /* [in]  Handle to heap to enumerate */
+              LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
+) {
+    NTSTATUS ret = RtlWalkHeap( heap, entry );
+    if (ret) SetLastError( RtlNtStatusToDosError(ret) );
+    return !ret;
+}
+
+
+/***********************************************************************
+ *           GetProcessHeap    (KERNEL32.@)
+ */
+HANDLE WINAPI GetProcessHeap(void)
+{
+    HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
+    return pdb[0x18 / sizeof(HANDLE)];  /* get dword at offset 0x18 in pdb */
+}
+
+
+/***********************************************************************
+ *           GetProcessHeaps    (KERNEL32.@)
+ */
+DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
+{
+    return RtlGetProcessHeaps( count, heaps );
+}
+
+
+/***********************************************************************
+ * 32-bit local heap functions (Win95; undocumented)
+ */
+
 /***********************************************************************
  *           K208   (KERNEL.208)
  */
@@ -1713,7 +271,7 @@
     DWORD totSize, segSize = 0;
     LPBYTE base;
     LOCAL32HEADER *header;
-    HEAP *heap;
+    HANDLE heap;
     WORD *selectorTable;
     WORD selectorEven, selectorOdd;
     int i, nrBlocks;
@@ -1748,8 +306,7 @@
         return 0;
     }
 
-    heap = (HEAP *)(base + segSize + HTABLE_SIZE);
-    if ( !HEAP_InitSubHeap( heap, (LPVOID)heap, 0, 0x10000, heapSize ) )
+    if (!(heap = RtlCreateHeap( 0, base + segSize + HTABLE_SIZE, heapSize, 0x10000, NULL, NULL )))
     {
         VirtualFree( base, 0, MEM_RELEASE );
         return 0;
@@ -1763,7 +320,7 @@
     header->limit   = HTABLE_PAGESIZE-1;
     header->flags   = 0;
     header->magic   = LOCAL32_MAGIC;
-    header->heap    = (HANDLE)heap;
+    header->heap    = heap;
 
     header->freeListFirst[0] = sizeof(LOCAL32HEADER);
     header->freeListLast[0]  = HTABLE_PAGESIZE - 4;
@@ -2146,8 +703,7 @@
  */
 BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
 {
-    SUBHEAP *heapPtr;
-    LPBYTE ptr;
+    PROCESS_HEAP_ENTRY entry;
     int i;
 
     LOCAL32HEADER *header = Local32_GetHeap( handle );
@@ -2156,31 +712,24 @@
     if ( !pLocal32Info || pLocal32Info->dwSize < sizeof(LOCAL32INFO) )
         return FALSE;
 
-    heapPtr = (SUBHEAP *)HEAP_GetPtr( header->heap );
-    pLocal32Info->dwMemReserved = heapPtr->size;
-    pLocal32Info->dwMemCommitted = heapPtr->commitSize;
-    pLocal32Info->dwTotalFree = 0L;
-    pLocal32Info->dwLargestFreeBlock = 0L;
+    pLocal32Info->dwMemReserved = 0;
+    pLocal32Info->dwMemCommitted = 0;
+    pLocal32Info->dwTotalFree = 0;
+    pLocal32Info->dwLargestFreeBlock = 0;
 
-    /* Note: Local32 heaps always have only one subheap! */
-    ptr = (LPBYTE)heapPtr + heapPtr->headerSize;
-    while ( ptr < (LPBYTE)heapPtr + heapPtr->size )
+    while (HeapWalk( header->heap, &entry ))
     {
-        if (*(DWORD *)ptr & ARENA_FLAG_FREE)
+        if (entry.wFlags & PROCESS_HEAP_REGION)
         {
-            ARENA_FREE *pArena = (ARENA_FREE *)ptr;
-            DWORD size = (pArena->size & ARENA_SIZE_MASK);
-            ptr += sizeof(*pArena) + size;
-
-            pLocal32Info->dwTotalFree += size;
-            if ( size > pLocal32Info->dwLargestFreeBlock )
-                pLocal32Info->dwLargestFreeBlock = size;
+            pLocal32Info->dwMemReserved += entry.u.Region.dwCommittedSize
+                                           + entry.u.Region.dwUnCommittedSize;
+            pLocal32Info->dwMemCommitted = entry.u.Region.dwCommittedSize;
         }
-        else
+        else if (!(entry.wFlags & PROCESS_HEAP_ENTRY_BUSY))
         {
-            ARENA_INUSE *pArena = (ARENA_INUSE *)ptr;
-            DWORD size = (pArena->size & ARENA_SIZE_MASK);
-            ptr += sizeof(*pArena) + size;
+            DWORD size = entry.cbData + entry.cbOverhead;
+            pLocal32Info->dwTotalFree += size;
+            if (size > pLocal32Info->dwLargestFreeBlock) pLocal32Info->dwLargestFreeBlock = size;
         }
     }
 
diff --git a/memory/selector.c b/memory/selector.c
index c3ce313..e68a92f 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -518,6 +518,84 @@
  *
  */
 
+struct mapls_entry
+{
+    struct mapls_entry *next;
+    void               *addr;   /* linear address */
+    int                 count;  /* ref count */
+    WORD                sel;    /* selector */
+};
+
+static struct mapls_entry *first_entry;
+
+
+/***********************************************************************
+ *           MapLS   (KERNEL32.@)
+ *           MapLS   (KERNEL.358)
+ *
+ * Maps linear pointer to segmented.
+ */
+SEGPTR WINAPI MapLS( LPCVOID ptr )
+{
+    struct mapls_entry *entry, *free = NULL;
+    void *base;
+    SEGPTR ret = 0;
+
+    if (!HIWORD(ptr)) return (SEGPTR)ptr;
+
+    base = (char *)ptr - ((unsigned int)ptr & 0x7fff);
+    HeapLock( GetProcessHeap() );
+    for (entry = first_entry; entry; entry = entry->next)
+    {
+        if (entry->addr == base) break;
+        if (!entry->count) free = entry;
+    }
+
+    if (!entry)
+    {
+        if (!free)  /* no free entry found, create a new one */
+        {
+            if (!(free = HeapAlloc( GetProcessHeap(), 0, sizeof(*free) ))) goto done;
+            if (!(free->sel = SELECTOR_AllocBlock( base, 0x10000, WINE_LDT_FLAGS_DATA )))
+            {
+                HeapFree( GetProcessHeap(), 0, free );
+                goto done;
+            }
+            free->count = 0;
+            free->next = first_entry;
+            first_entry = free;
+        }
+        SetSelectorBase( free->sel, (DWORD)base );
+        free->addr = base;
+        entry = free;
+    }
+    entry->count++;
+    ret = MAKESEGPTR( entry->sel, (char *)ptr - (char *)entry->addr );
+ done:
+    HeapUnlock( GetProcessHeap() );
+    return ret;
+}
+
+/***********************************************************************
+ *           UnMapLS   (KERNEL32.@)
+ *           UnMapLS   (KERNEL.359)
+ *
+ * Free mapped selector.
+ */
+void WINAPI UnMapLS( SEGPTR sptr )
+{
+    struct mapls_entry *entry;
+    WORD sel = SELECTOROF(sptr);
+
+    if (sel)
+    {
+        HeapLock( GetProcessHeap() );
+        for (entry = first_entry; entry; entry = entry->next) if (entry->sel == sel) break;
+        if (entry && entry->count > 0) entry->count--;
+        HeapUnlock( GetProcessHeap() );
+    }
+}
+
 /***********************************************************************
  *           MapSL   (KERNEL32.@)
  *           MapSL   (KERNEL.357)