- Rewrote Base Heap implementation nearly from scratch, currently only for Global...
authorAlex Ionescu <aionescu@gmail.com>
Sat, 24 Jun 2006 18:11:57 +0000 (18:11 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Sat, 24 Jun 2006 18:11:57 +0000 (18:11 +0000)
- Main changes include using the RtlHandle package instead of duplicating an internal implementation, as well as using the RtlHeap* APIs that allow for setting User Flags/Values for associating Base Heap Flags/Handles with the actual RTL-managed block.
- Regression-tested with WINE tests and basic ROS apps.

svn path=/trunk/; revision=22579

reactos/dll/win32/kernel32/include/baseheap.h [new file with mode: 0644]
reactos/dll/win32/kernel32/include/kernel32.h
reactos/dll/win32/kernel32/mem/global.c
reactos/dll/win32/kernel32/misc/dllmain.c

diff --git a/reactos/dll/win32/kernel32/include/baseheap.h b/reactos/dll/win32/kernel32/include/baseheap.h
new file mode 100644 (file)
index 0000000..b06c064
--- /dev/null
@@ -0,0 +1,121 @@
+/*\r
+ * PROJECT:         ReactOS Win32 Base API\r
+ * LICENSE:         GPL - See COPYING in the top level directory\r
+ * FILE:            dll/win32/kernel32/include/baseheap.h\r
+ * PURPOSE:         Base Heap Structures\r
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
+ */\r
+\r
+//\r
+// Some important implementation notes.\r
+//\r
+// Firstly, the Global* APIs in Win32 are largely similar to the Local* APIs,\r
+// but there are a number of small differences (for example, there is no such\r
+// thing as DDE/Shared Local memory, and the re-allocation semantics are also\r
+// simpler, because you cannot force a move).\r
+//\r
+// Note something VERY IMPORTANT: This implementation *depends* on the fact\r
+// that all heap pointers are, at the very least, 8 byte aligned, and that heap\r
+// handles are actually pointers inside our HandleEntry->Object, which happens\r
+// to be at offset 0x4, which means testing with bit 3 tells us if the handle\r
+// is a pointer or a real "handle". On 64-bit, heap pointers should be 16-byte\r
+// aligned, and our offset should be 0x8, so the trick works anyways, but using\r
+// the 4th bit.\r
+//\r
+// Apart from MSDN, a wonderful source of information about how this works is\r
+// available on Raymond's blog, in a 4-parter series starting at:\r
+// http://blogs.msdn.com/oldnewthing/archive/2004/11/04/252258.aspx.\r
+//\r
+// Finally, as Raymond points out, be aware that some applications depend on\r
+// the way this implementation was done, since global memory handles are a\r
+// straight-forward overlay on top of the RTL Handle implementation, and rogue\r
+// applications can easily do the conversion manually without calling the right\r
+// API for it (such as GlobalLock).\r
+//\r
+\r
+//\r
+// The Handle Table\r
+//\r
+extern RTL_HANDLE_TABLE BaseGlobalHandleTable;\r
+\r
+//\r
+// Tracing Support\r
+// Define _BASE_HANDLE_TRACE for Traces\r
+//\r
+#ifdef _BASE_HANDLE_TRACE_\r
+#define BH_PRINT DbgPrint\r
+#else\r
+#define BH_PRINT DPRINT\r
+#endif\r
+#define BASE_TRACE_ALLOC(x, y)                                              \\r
+    BH_PRINT("[BASE_HEAP] %s : Allocating %lx bytes with flags: %lx\n",     \\r
+             __FUNCTION__, x, y)\r
+#define BASE_TRACE_ALLOC2(x)                                                \\r
+    BH_PRINT("[BASE_HEAP] %s : Allocated %p\n",                             \\r
+             __FUNCTION__, x)\r
+#define BASE_TRACE_PTR(x, y)                                                \\r
+    BH_PRINT("[BASE_HEAP] %s : Using handle: %lx for pointer: %p\n",        \\r
+             __FUNCTION__, x, y)\r
+#define BASE_TRACE_HANDLE(x, y)                                             \\r
+    BH_PRINT("[BASE_HEAP] %s : Using handle: %lx for block: %p\n",          \\r
+             __FUNCTION__, x, y)\r
+#define BASE_TRACE_DEALLOC(x)                                               \\r
+    BH_PRINT("[BASE_HEAP] %s : Freeing %p\n",                               \\r
+             __FUNCTION__, x)\r
+\r
+//\r
+// The handle structure for global heap handles.\r
+// Notice that it nicely overlays with RTL_HANDLE_ENTRY.\r
+// KEEP IT THAT WAY! ;-)\r
+//\r
+typedef struct _GLOBAL_HEAP_HANDLE_ENTRY\r
+{\r
+    USHORT Flags;\r
+    USHORT LockCount;\r
+    union\r
+    {\r
+        PVOID Object;\r
+        ULONG OldSize;\r
+    };\r
+} GLOBAL_HEAP_HANDLE_ENTRY, *PGLOBAL_HEAP_HANDLE_ENTRY;\r
+\r
+//\r
+// Handle entry flags\r
+// Note that 0x0001 is the shared/generic RTL_HANDLE_VALID\r
+//\r
+#define GLOBAL_HEAP_ENTRY_FLAG_MOVABLE      0x0002\r
+#define GLOBAL_HEAP_ENTRY_FLAG_REUSABLE     0x0004\r
+#define GLOBAL_HEAP_ENTRY_FLAG_REUSE        0x0008\r
+#define GLOBAL_HEAP_ENTRY_FLAG_DDESHARE     0x0010\r
+\r
+//\r
+// Easy way to check if the global handle is actually an entry in our table\r
+//\r
+#define GLOBAL_HEAP_IS_HANDLE_ENTRY         \\r
+    (ULONG_PTR)FIELD_OFFSET(GLOBAL_HEAP_HANDLE_ENTRY, Object)\r
+\r
+//\r
+// Tags for the entire heap allocation for this global memory.\r
+// They are set part of the User Flags of the RTL Heap.\r
+//\r
+#define GLOBAL_HEAP_FLAG_MOVABLE            HEAP_SETTABLE_USER_FLAG1\r
+#define GLOBAL_HEAP_FLAG_DDESHARE           HEAP_SETTABLE_USER_FLAG2\r
+\r
+//\r
+// Internal Handle Functions\r
+//\r
+#define GlobalAllocEntry()                  \\r
+    (PGLOBAL_HEAP_HANDLE_ENTRY)RtlAllocateHandle(&BaseGlobalHandleTable, NULL)\r
+\r
+#define GlobalGetEntry(h)                   \\r
+    (PGLOBAL_HEAP_HANDLE_ENTRY)             \\r
+        CONTAINING_RECORD(h,                \\r
+            GLOBAL_HEAP_HANDLE_ENTRY,       \\r
+            Object);\r
+\r
+#define GlobalValidateEntry(he)             \\r
+    RtlIsValidHandle(&BaseGlobalHandleTable, (PRTL_HANDLE_TABLE_ENTRY)he)\r
+\r
+#define GlobalFreeEntry(he)                 \\r
+    RtlFreeHandle(&BaseGlobalHandleTable, (PRTL_HANDLE_TABLE_ENTRY)he);\r
+\r
index 3e14ead..5decc1c 100755 (executable)
@@ -1,6 +1,8 @@
 #ifndef _KERNEL32_INCLUDE_KERNEL32_H
 #define _KERNEL32_INCLUDE_KERNEL32_H
 
+#include "baseheap.h"
+
 #define BINARY_UNKNOWN (0)
 #define BINARY_PE_EXE32        (1)
 #define BINARY_PE_DLL32        (2)
index da213ab..873d78d 100644 (file)
-/* $Id$
- *
- * Win32 Global/Local heap functions (GlobalXXX, LocalXXX).
- * These functions included in Win32 for compatibility with 16 bit Windows
- * Especially the moveable blocks and handles are oldish.
- * But the ability to directly allocate memory with GPTR and LPTR is widely
- * used.
- *
- * Updated to support movable memory with algorithms taken from wine.
+/*
+ * PROJECT:         ReactOS Win32 Base API
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            dll/win32/kernel32/mem/global.c
+ * PURPOSE:         Global Memory APIs (sits on top of Heap*)
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  */
 
+/* INCLUDES ******************************************************************/
+
 #include <k32.h>
 
 #define NDEBUG
-#include "../include/debug.h"
-
-#ifdef _GNUC_
-#define STRUCT_PACK __attribute__((packed))
-#else
-#define STRUCT_PACK
-#endif
+#include "debug.h"
 
-#define MAGIC_GLOBAL_USED 0x5342BEEF
-#define GLOBAL_LOCK_MAX   0xFF
-
-/*Wine found that some applications complain if memory isn't 8 byte aligned.
-* We make use of that experience here.
-*/
-#define HANDLE_SIZE          8  /*sizeof(HANDLE) *2 */
-
-
-typedef struct __GLOBAL_LOCAL_HANDLE
-{
-    DWORD   Magic;
-    LPVOID  Pointer; STRUCT_PACK
-    BYTE    Flags;
-    BYTE    LockCount;
-} GLOBAL_HANDLE, LOCAL_HANDLE, *PGLOBAL_HANDLE, *PLOCAL_HANDLE;
-
-#define HANDLE_TO_INTERN(h)  ((PGLOBAL_HANDLE)(((char *)(h))-4))
-#define INTERN_TO_HANDLE(i)  ((HGLOBAL) &((i)->Pointer))
-#define POINTER_TO_HANDLE(p) (*(PHANDLE)((ULONG_PTR)p - HANDLE_SIZE))
-#define ISHANDLE(h)          ((((ULONG)(h)) & 0x4)!=0)
-#define ISPOINTER(h)         ((((ULONG)(h)) & 0x4)==0)
-
-
-static void DbgPrintStruct(PGLOBAL_HANDLE h)
-{
-    DPRINT("Magic:     0x%X\n", h->Magic);
-    DPRINT("Pointer:   0x%X\n", h->Pointer);
-    DPRINT("Flags:     0x%X\n", h->Flags);
-    DPRINT("LockCount: 0x%X\n", h->LockCount);
-}
+#define BASE_TRACE_FAILURE()                                                 \
+    DbgPrint("[BASE_HEAP] %s : Failing %d\n",                                \
+             __FUNCTION__, __LINE__)
 
+/* TYPES *********************************************************************/
 
+extern SYSTEM_BASIC_INFORMATION BaseCachedSysInfo;
+RTL_HANDLE_TABLE BaseGlobalHandleTable;
 
 /* FUNCTIONS ***************************************************************/
 
 /*
  * @implemented
  */
-HGLOBAL STDCALL
+HGLOBAL
+NTAPI
 GlobalAlloc(UINT uFlags,
             DWORD dwBytes)
 {
+    ULONG Flags = 0;
+    PVOID Ptr = NULL;
+    HANDLE hMemory;
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    BASE_TRACE_ALLOC(dwBytes, uFlags);
+    ASSERT(hProcessHeap);
+
+    /* Make sure the flags are valid */
+    if (uFlags & ~GMEM_VALID_FLAGS)
+    {
+        /* They aren't, fail */
+        BASE_TRACE_FAILURE();
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
+    }
 
-    PGLOBAL_HANDLE phandle    = 0;
-    PVOID          palloc     = 0;
-    UINT           heap_flags = 0;
+    /* Convert ZEROINIT */
+    if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
 
-    if (uFlags & GMEM_ZEROINIT)
+    /* Check if we're not movable, which means pointer-based heap */
+    if (!(uFlags & GMEM_MOVEABLE))
     {
-        heap_flags = HEAP_ZERO_MEMORY;
+        /* Check if this is DDESHARE (deprecated) */
+        if (uFlags & GMEM_DDESHARE) Flags |= GLOBAL_HEAP_ENTRY_FLAG_DDESHARE;
+
+        /* Allocate heap for it */
+        Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
+        BASE_TRACE_ALLOC2(Ptr);
+        return Ptr;
     }
 
-    DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", uFlags, dwBytes);
+    /* This is heap based, so lock it in first */
+    RtlLockHeap(hProcessHeap);
+
+    /*
+     * Disable locking, enable custom flags, and write the
+     * movable flag (deprecated)
+     */
+    Flags |= HEAP_NO_SERIALIZE |
+             HEAP_SETTABLE_USER_VALUE |
+             GLOBAL_HEAP_FLAG_MOVABLE;
 
-    //Changed hProcessHeap to GetProcessHeap()
-    if ((uFlags & GMEM_MOVEABLE)==0) /* POINTER */
+    /* Allocate the handle */
+    HandleEntry = GlobalAllocEntry();
+    if (!HandleEntry)
     {
-        palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes);
-        if (! ISPOINTER(palloc))
+        /* Fail */
+        hMemory = NULL;
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        BASE_TRACE_FAILURE();
+        goto Quickie;
+    }
+
+    /* Get the object and make sure we have size */
+    hMemory = &HandleEntry->Object;
+    if (dwBytes)
+    {
+        /* Allocate the actual memory for it */
+        Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
+        BASE_TRACE_PTR(HandleEntry, Ptr);
+        if (!Ptr)
         {
-            DPRINT1("GlobalAlloced pointer which is not 8-byte aligned\n");
-            RtlFreeHeap(GetProcessHeap(), 0, palloc);
-            return NULL;
+            /* We failed, manually set the allocate flag and free the handle */
+            HandleEntry->Flags = RTL_HANDLE_VALID;
+            GlobalFreeEntry(HandleEntry);
+
+            /* For the cleanup case */
+            HandleEntry = NULL;
+        }
+        else
+        {
+            /* All worked well, save our heap entry */
+            RtlSetUserValueHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
         }
-        return (HGLOBAL) palloc;
     }
-    else  /* HANDLE */
+
+Quickie:
+    /* Cleanup! First unlock the heap */
+    RtlUnlockHeap(hProcessHeap);
+
+    /* Check if a handle was allocated */
+    if (HandleEntry)
     {
-        HeapLock(hProcessHeap);
+        /* Set the pointer and allocated flag */
+        HandleEntry->Object = Ptr;
+        HandleEntry->Flags = RTL_HANDLE_VALID;
+        if (!Ptr)
+        {
+            /* We don't have a valid pointer, but so reuse this handle */
+            HandleEntry->Flags = GLOBAL_HEAP_ENTRY_FLAG_REUSE;
+        }
 
-        phandle = RtlAllocateHeap(GetProcessHeap(), 0,  sizeof(GLOBAL_HANDLE));
-        if (phandle)
+        /* Check if the handle is discardable */
+        if (uFlags & GMEM_DISCARDABLE)
         {
-            phandle->Magic     = MAGIC_GLOBAL_USED;
-            phandle->Flags     = uFlags >> 8;
-            phandle->LockCount = 0;
-            phandle->Pointer   = 0;
+            /* Save it in the handle entry */
+            HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
+        }
 
-            if (dwBytes)
-            {
-                palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes + HANDLE_SIZE);
-                if (palloc)
-                {
-                    *(PHANDLE)palloc = INTERN_TO_HANDLE(phandle);
-                    phandle->Pointer = (PVOID)((ULONG_PTR)palloc + HANDLE_SIZE);
-                }
-                else /*failed to allocate the memory block*/
-                {
-                    RtlFreeHeap(GetProcessHeap(), 0, phandle);
-                    phandle = 0;
-                }
-            }
-            else
-            {
-                DPRINT("Allocated a 0 size movable block.\n");
-                DbgPrintStruct(phandle);
-                DPRINT("Address of the struct: 0x%X\n", phandle);
-                DPRINT("Address of pointer:    0x%X\n", &(phandle->Pointer));
-            }
+        /* Check if the handle is moveable */
+        if (uFlags & GMEM_MOVEABLE)
+        {
+            /* Save it in the handle entry */
+            HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_MOVABLE;
         }
-        HeapUnlock(hProcessHeap);
 
-        if (phandle)
+        /* Check if the handle is DDE Shared */
+        if (uFlags & GMEM_DDESHARE)
         {
-            if (ISPOINTER(INTERN_TO_HANDLE(phandle)))
-            {
-                DPRINT1("GlobalAlloced handle which is 8-byte aligned but shouldn't be\n");
-                RtlFreeHeap(GetProcessHeap(), 0, palloc);
-                RtlFreeHeap(GetProcessHeap(), 0, phandle);
-                return NULL;
-            }
-            return INTERN_TO_HANDLE(phandle);
+            /* Save it in the handle entry */
+            HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_DDESHARE;
         }
-        else
-            return (HGLOBAL)0;
+
+        /* Set the pointer */
+        Ptr = hMemory;
     }
-}
 
+    /* Return the pointer */
+    return Ptr;
+}
 
 /*
  * @implemented
  */
-SIZE_T STDCALL
+SIZE_T
+NTAPI
 GlobalCompact(DWORD dwMinFree)
 {
-   return RtlCompactHeap(hProcessHeap, 0);
+    /* Call the RTL Heap Manager */
+    return RtlCompactHeap(hProcessHeap, 0);
 }
 
-
 /*
  * @implemented
  */
-VOID STDCALL
+VOID
+NTAPI
 GlobalFix(HGLOBAL hMem)
 {
-   if (INVALID_HANDLE_VALUE != hMem)
-     GlobalLock(hMem);
+    /* Lock the memory if it the handle is valid */
+    if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem);
 }
 
 /*
  * @implemented
  */
-UINT STDCALL
+UINT
+NTAPI
 GlobalFlags(HGLOBAL hMem)
 {
-    DWORD                  retval;
-    PGLOBAL_HANDLE     phandle;
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    HANDLE Handle = NULL;
+    ULONG Flags = 0;
+    UINT uFlags = GMEM_INVALID_HANDLE;
 
-    DPRINT("GlobalFlags( 0x%lX )\n", (ULONG)hMem);
+    /* Start by locking the heap */
+    RtlLockHeap(hProcessHeap);
 
-    if(!ISHANDLE(hMem))
+    /* Check if this is a simple RTL Heap Managed block */
+    if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
     {
-        DPRINT("GlobalFlags: Fixed memory.\n");
-        retval = 0;
-    }
-    else
-    {
-        HeapLock(GetProcessHeap());
-
-        phandle = HANDLE_TO_INTERN(hMem);
-
-        /*DbgPrintStruct(phandle);*/
-
-        if (MAGIC_GLOBAL_USED == phandle->Magic)
+        /* Then we'll query RTL Heap */
+        RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
+        BASE_TRACE_PTR(Handle, hMem);
+
+        /*
+         * Check if RTL Heap didn't find a handle associated with us or
+         * said that this heap isn't movable, which means something we're
+         * really not a handle-based heap.
+         */
+        if (!(Handle) || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
         {
-            /*DbgPrint("GlobalFlags: Magic number ok\n");
-            **DbgPrint("GlobalFlags: pointer is 0x%X\n", phandle->Pointer);
-            */
-            retval = phandle->LockCount + (phandle->Flags << 8);
-            if (0 == phandle->Pointer)
-            {
-                retval = retval | GMEM_DISCARDED;
-            }
+            /* Then set the flags to 0 */
+            uFlags = 0;
         }
         else
         {
-            DPRINT1("GlobalSize: invalid handle\n");
-            retval = 0;
+            /* Otherwise we're handle-based, so get the internal handle */
+            hMem = Handle;
         }
-        HeapUnlock(GetProcessHeap());
     }
-    return retval;
-}
 
-
-/*
- * @implemented
- */
-HGLOBAL STDCALL
-GlobalFree(HGLOBAL hMem)
-{
-    PGLOBAL_HANDLE phandle;
-    HGLOBAL hreturned;
-
-    DPRINT("GlobalFree( 0x%lX )\n", (ULONG)hMem);
-
-    hreturned = 0;
-    if (ISPOINTER(hMem)) /* POINTER */
+    /* Check if the handle is actually an entry in our table */
+    if ((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)
     {
-        if(!RtlFreeHeap(GetProcessHeap(), 0, (PVOID)hMem))
-            hMem = 0;
-    }
-    else /* HANDLE */
-    {
-        HeapLock(GetProcessHeap());
+        /* Then get the entry */
+        HandleEntry = GlobalGetEntry(hMem);
+        BASE_TRACE_HANDLE(HandleEntry, hMem);
 
-        phandle = HANDLE_TO_INTERN(hMem);
-
-        if(MAGIC_GLOBAL_USED == phandle->Magic)
+        /* Make sure it's a valid handle */
+        if (GlobalValidateEntry(HandleEntry))
         {
-            /* WIN98 does not make this test. That is you can free a */
-            /* block you have not unlocked. Go figure!!              */
-            if(phandle->LockCount!=0)
+            /* Get the lock count first */
+            uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
+
+            /* Now check if it's discarded */
+            if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_REUSABLE)
             {
-                DPRINT1("Warning! GlobalFree(0x%X) Freeing a handle to a locked object.\n", hMem);
-                SetLastError(ERROR_INVALID_HANDLE);
+                /* Set the Win32 Flag */
+                uFlags |= GMEM_DISCARDED;
             }
 
-            if(phandle->Pointer)
-                if (!RtlFreeHeap(GetProcessHeap(), 0, (PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE)))
-                    hreturned = hMem;
+            /* Check if it's movable */
+            if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_MOVABLE)
+            {
+                /* Set the Win32 Flag */
+                uFlags |= GMEM_MOVEABLE;
+            }
 
-            if (!RtlFreeHeap(GetProcessHeap(), 0, phandle))
-                hreturned = hMem;
+            /* Check if it's DDE Shared */
+            if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_DDESHARE)
+            {
+                /* Set the Win32 Flag */
+                uFlags |= GMEM_DDESHARE;
+            }
         }
-        HeapUnlock(GetProcessHeap());
-
-        hMem = 0;
     }
-    return hreturned;
-}
 
+    /* Check if by now, we still haven't gotten any useful flags */
+    if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
+
+    /* All done! Unlock heap and return Win32 Flags */
+    RtlUnlockHeap(hProcessHeap);
+    return uFlags;
+}
 
 /*
  * @implemented
  */
-HGLOBAL STDCALL
-GlobalHandle(LPCVOID pMem)
+HGLOBAL
+NTAPI
+GlobalFree(HGLOBAL hMem)
 {
-    HGLOBAL              handle = 0;
-    PGLOBAL_HANDLE         test = 0;
-    LPCVOID        pointer_test = 0;
-
-    DPRINT("GlobalHandle( 0x%lX )\n", (ULONG)pMem);
-    if (0 == pMem) /*Invalid argument */
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        DPRINT1("Error: 0 handle.\n");
-        return 0;
-    }
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    LPVOID Ptr;
+    BASE_TRACE_DEALLOC(hMem);
 
-    HeapLock(GetProcessHeap());
-    /* Now test to see if this pointer is associated with a handle.
-    * This is done by calling RtlValidateHeap() and seeing if it fails.
-    */
-    if (RtlValidateHeap(GetProcessHeap(), 0, (char *)pMem)) /*FIXED*/
-    {
-        handle = (HGLOBAL)pMem;
-        return handle;
-    }
-    else /*MOVABLE*/
+    /* Check if this was a simple allocated heap entry */
+    if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
     {
-        handle = POINTER_TO_HANDLE(pMem);
+        /* Free it with the RTL Heap Manager */
+        if (RtlFreeHeap(hProcessHeap, 0, hMem))
+        {
+            /* Return NULL since there's no handle */
+            return NULL;
+        }
+        else
+        {
+            /* Otherwise fail */
+            BASE_TRACE_FAILURE();
+            SetLastError(ERROR_INVALID_HANDLE);
+            return hMem;
+        }
     }
 
+    /* It's a handle probably, so lock the heap */
+    RtlLockHeap(hProcessHeap);
 
-    /* Test to see if this memory is valid*/
-    test  = HANDLE_TO_INTERN(handle);
-    if (!IsBadReadPtr(test, sizeof(GLOBAL_HANDLE)))
+    /* Make sure that this is an entry in our handle database */
+    if ((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)
     {
-        if (MAGIC_GLOBAL_USED == test->Magic)
+        /* Get the entry */
+        HandleEntry = GlobalGetEntry(hMem);
+        BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+        /* Make sure the handle is valid */
+        if (!GlobalValidateEntry(HandleEntry))
         {
-            pointer_test = test->Pointer;
-            if (!RtlValidateHeap(GetProcessHeap(), 0, ((char *)pointer_test) - HANDLE_SIZE) ||
-                !RtlValidateHeap(GetProcessHeap(), 0, test))
-            {
-                SetLastError(ERROR_INVALID_HANDLE);
-                handle = 0;
-            }
+            /* It's not, fail */
+            SetLastError(ERROR_INVALID_HANDLE);
+            Ptr = NULL;
+        }
+        else
+        {
+            /* It's valid, so get the pointer */
+            Ptr = HandleEntry->Object;
+
+            /* Free this handle */
+            GlobalFreeEntry(HandleEntry);
+
+            /* If the pointer is 0, then we don't have a handle either */
+            if (!Ptr) hMem = NULL;
         }
     }
     else
     {
-        DPRINT1("GlobalHandle: Bad read pointer.\n");
-        SetLastError(ERROR_INVALID_HANDLE);
-        handle = 0;
+        /* Otherwise, reuse the handle as a pointer */
+        BASE_TRACE_FAILURE();
+        Ptr = hMem;
     }
 
-    HeapUnlock(GetProcessHeap());
+    /* Check if we got here with a valid heap pointer */
+    if (Ptr)
+    {
+        /* Free it */
+        RtlFreeHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr);
+        hMem = NULL;
+    }
 
-    return handle;
+    /* We're done, so unlock the heap and return the handle */
+    RtlUnlockHeap(hProcessHeap);
+    return hMem;
 }
 
-
 /*
  * @implemented
  */
-LPVOID STDCALL
-GlobalLock(HGLOBAL hMem)
+HGLOBAL
+NTAPI
+GlobalHandle(LPCVOID pMem)
 {
-    PGLOBAL_HANDLE phandle;
-    LPVOID         palloc;
-
-    DPRINT("GlobalLock( 0x%lX )\n", (ULONG)hMem);
-
-    if (ISPOINTER(hMem))
-        return (LPVOID) hMem;
-
-    HeapLock(GetProcessHeap());
-
-    phandle = HANDLE_TO_INTERN(hMem);
-
-    if(MAGIC_GLOBAL_USED == phandle->Magic)
+    HANDLE Handle = NULL;
+    ULONG Flags;
+
+    /* Lock the heap */
+    RtlLockHeap(hProcessHeap);
+
+    /* Query RTL Heap */
+    RtlGetUserInfoHeap(hProcessHeap,
+                       HEAP_NO_SERIALIZE,
+                       (PVOID)pMem,
+                       &Handle,
+                       &Flags);
+    BASE_TRACE_PTR(Handle, pMem);
+
+    /*
+     * Check if RTL Heap didn't find a handle for us or said that
+     * this heap isn't movable.
+     */
+    if (!(Handle) || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
     {
-        if(GLOBAL_LOCK_MAX > phandle->LockCount)
-        {
-            phandle->LockCount++;
-        }
-        palloc = phandle->Pointer;
+        /* We're actually handle-based, so the pointer is a handle */
+        Handle = (HANDLE)pMem;
     }
-    else
-    {
-        DPRINT("GlobalLock: invalid handle\n");
-        palloc = (LPVOID) hMem;
-    }
-
-    HeapUnlock(GetProcessHeap());
 
-    return palloc;
+    /* All done, unlock the heap and return the handle */
+    RtlUnlockHeap(hProcessHeap);
+    return Handle;
 }
 
 /*
  * @implemented
  */
-BOOL
-STDCALL
-GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
+LPVOID
+NTAPI
+GlobalLock(HGLOBAL hMem)
 {
-  SYSTEM_BASIC_INFORMATION     SysBasicInfo;
-  SYSTEM_PERFORMANCE_INFORMATION       SysPerfInfo;
-  ULONG UserMemory;
-  NTSTATUS Status;
-
-    DPRINT("GlobalMemoryStatusEx\n");
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    LPVOID Ptr;
 
-    if (lpBuffer->dwLength != sizeof(MEMORYSTATUSEX))
-      {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-      }
-
-   Status = ZwQuerySystemInformation(SystemBasicInformation,
-                                     &SysBasicInfo,
-                                     sizeof(SysBasicInfo),
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FALSE;
-     }
-
-   Status = ZwQuerySystemInformation(SystemPerformanceInformation,
-                                     &SysPerfInfo,
-                                     sizeof(SysPerfInfo),
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FALSE;
-     }
-
-   Status = ZwQuerySystemInformation(SystemFullMemoryInformation,
-                                     &UserMemory,
-                                     sizeof(ULONG),
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       SetLastErrorByStatus(Status);
-       return FALSE;
-     }
-
-/*
- * Load percentage 0 thru 100. 0 is good and 100 is bad.
- *
- *     Um = allocated memory / physical memory
- *     Um =      177 MB      /     256 MB        = 69.1%
- *
- *     Mult allocated memory by 100 to move decimal point up.
- */
-   lpBuffer->dwMemoryLoad = (SysBasicInfo.NumberOfPhysicalPages -
-                            SysPerfInfo.AvailablePages) * 100 /
-                            SysBasicInfo.NumberOfPhysicalPages;
-
-   DPRINT1("Memory Load: %d%%\n",lpBuffer->dwMemoryLoad );
-
-   lpBuffer->ullTotalPhys = SysBasicInfo.NumberOfPhysicalPages *
-                                       SysBasicInfo.PageSize;
-   lpBuffer->ullAvailPhys = SysPerfInfo.AvailablePages *
-                                       SysBasicInfo.PageSize;
-
-       DPRINT("%d\n",SysPerfInfo.AvailablePages );
-       DPRINT("%d\n",lpBuffer->ullAvailPhys );
-
-   lpBuffer->ullTotalPageFile = SysPerfInfo.CommitLimit *
-                                       SysBasicInfo.PageSize;
-
-       DPRINT("%d\n",lpBuffer->ullTotalPageFile );
-
-   lpBuffer->ullAvailPageFile = ((SysPerfInfo.CommitLimit -
-                                       SysPerfInfo.CommittedPages) *
-                                       SysBasicInfo.PageSize);
-
-/* VM available to the calling processes, User Mem? */
-   lpBuffer->ullTotalVirtual = SysBasicInfo.MaximumUserModeAddress -
-                                       SysBasicInfo.MinimumUserModeAddress;
-
-   lpBuffer->ullAvailVirtual = (lpBuffer->ullTotalVirtual -
-                                       (UserMemory *
-                                        SysBasicInfo.PageSize));
+    /* Check if this was a simple allocated heap entry */
+    if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
+    {
+        /* Then simply return the pointer */
+        return hMem;
+    }
 
-       DPRINT("%d\n",lpBuffer->ullAvailVirtual );
-       DPRINT("%d\n",UserMemory);
-       DPRINT("%d\n",SysBasicInfo.PageSize);
+    /* Otherwise, lock the heap */
+    RtlLockHeap(hProcessHeap);
 
-/* lol! Memory from beyond! */
-   lpBuffer->ullAvailExtendedVirtual = 0;
-   return TRUE;
-}
+    /* Get the handle entry */
+    HandleEntry = GlobalGetEntry(hMem);
+    BASE_TRACE_HANDLE(HandleEntry, hMem);
 
-/*
- * @implemented
- */
-VOID STDCALL
-GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
-{
-    MEMORYSTATUSEX lpBufferEx;
-#if 0
-    if (lpBuffer->dwLength != sizeof(MEMORYSTATUS))
-      {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return;
-      }
-#endif
-    lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
+    /* Make sure it's valid */
+    if (!GlobalValidateEntry(HandleEntry))
+    {
+        /* It's not, fail */
+        BASE_TRACE_FAILURE();
+        SetLastError(ERROR_INVALID_HANDLE);
+        Ptr = NULL;
+    }
+    else
+    {
+        /* Otherwise, get the pointer */
+        Ptr = HandleEntry->Object;
+        if (Ptr)
+        {
+            /* Increase the lock count, unless we've went too far */
+            if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT)
+            {
+                /* In which case we simply unlock once */
+                HandleEntry->LockCount--;
+            }
+        }
+        else
+        {
+            /* The handle is still there but the memory was already freed */
+            SetLastError(ERROR_DISCARDED);
+        }
+    }
 
-    if (GlobalMemoryStatusEx(&lpBufferEx))
-      {
-
-        lpBuffer->dwLength        = sizeof(MEMORYSTATUS);
-
-         lpBuffer->dwMemoryLoad    = lpBufferEx.dwMemoryLoad;
-         lpBuffer->dwTotalPhys     = lpBufferEx.ullTotalPhys;
-         lpBuffer->dwAvailPhys     = lpBufferEx.ullAvailPhys;
-         lpBuffer->dwTotalPageFile = lpBufferEx.ullTotalPageFile;
-         lpBuffer->dwAvailPageFile = lpBufferEx.ullAvailPageFile;
-         lpBuffer->dwTotalVirtual  = lpBufferEx.ullTotalVirtual;
-         lpBuffer->dwAvailVirtual  = lpBufferEx.ullAvailVirtual;
-      }
+    /* All done. Unlock the heap and return the pointer */
+    RtlUnlockHeap(hProcessHeap);
+    return Ptr;
 }
 
-
-HGLOBAL STDCALL
+HGLOBAL
+NTAPI
 GlobalReAlloc(HGLOBAL hMem,
-             DWORD dwBytes,
-             UINT uFlags)
+              DWORD dwBytes,
+              UINT uFlags)
 {
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    HANDLE Handle;
+    LPVOID Ptr;
+    ULONG Flags = 0;
 
-    LPVOID         palloc = 0;
-    HGLOBAL        hnew = 0;
-    PGLOBAL_HANDLE phandle = 0;
-    ULONG          heap_flags = 0;
+    /* Convert ZEROINIT */
+    if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
 
-    DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG)hMem, dwBytes, uFlags);
+    /* If this wasn't a movable heap, then we MUST re-alloc in place */
+    if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
 
-    if (uFlags & GMEM_ZEROINIT)
-    {
-        heap_flags = HEAP_ZERO_MEMORY;
-    }
-
-    HeapLock(GetProcessHeap());
+    /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
+    RtlLockHeap(hProcessHeap);
+    Flags |= HEAP_NO_SERIALIZE;
+    DPRINT1("hmem: %p Flags: %lx\n", hMem, uFlags);
 
-    if(uFlags & GMEM_MODIFY) /* modify flags */
+    /* Check if this is a simple handle-based block */
+    if (((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
     {
-        if( ISPOINTER(hMem) && (uFlags & GMEM_MOVEABLE))
+        /* Get the entry */
+        HandleEntry = GlobalGetEntry(hMem);
+        BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+        /* Make sure the handle is valid */
+        if (!GlobalValidateEntry(HandleEntry))
         {
-            /* make a fixed block moveable
-            * actually only NT is able to do this. And it's soo simple
-            */
-            if (0 == hMem)
+            /* Fail */
+            BASE_TRACE_FAILURE();
+            SetLastError(ERROR_INVALID_HANDLE);
+            hMem = NULL;
+        }
+        else if (uFlags & GMEM_MODIFY)
+        {
+            /* User is changing flags... check if the memory was discardable */
+            if (uFlags & GMEM_DISCARDABLE)
             {
-                SetLastError( ERROR_NOACCESS );
-                hnew = 0;
+                /* Then set the flag */
+                HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
             }
             else
             {
-                dwBytes   = RtlSizeHeap(GetProcessHeap(), 0, (LPVOID) hMem);
-                hnew      = GlobalAlloc( uFlags, dwBytes);
-                palloc    = GlobalLock(hnew);
-                memcpy(palloc, (LPVOID) hMem, dwBytes);
-                GlobalUnlock(hnew);
-                RtlFreeHeap(GetProcessHeap(),0,hMem);
+                /* Otherwise, remove the flag */
+                HandleEntry->Flags &= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
             }
         }
-        else if(ISPOINTER(hMem) && (uFlags & GMEM_DISCARDABLE))
-        {
-            /* change the flags to make our block "discardable" */
-            phandle = HANDLE_TO_INTERN(hMem);
-            phandle->Flags = phandle->Flags | (GMEM_DISCARDABLE >> 8);
-            hnew = hMem;
-        }
         else
         {
-            SetLastError(ERROR_INVALID_PARAMETER);
-            hnew = 0;
-        }
-    }
-    else
-    {
-        if(ISPOINTER(hMem))
-        {
-            if (!(uFlags & GMEM_MOVEABLE))
+            /* Otherwise, get the object and check if we have no size */
+            Ptr = HandleEntry->Object;
+            if (!dwBytes)
             {
-                heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
+                /* Clear the handle and check for a pointer */
+                hMem = NULL;
+                if (Ptr)
+                {
+                    /* Make sure the handle isn't locked */
+                    if ((uFlags & GMEM_MOVEABLE) & !(HandleEntry->LockCount))
+                    {
+                        /* Free the current heap */
+                        RtlFreeHeap(hProcessHeap, Flags, Ptr);
+
+                        /* Free the handle */
+                        HandleEntry->Object = NULL;
+                        HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSE;
+
+                        /* Get the object pointer */
+                        hMem = &HandleEntry->Object;
+                    }
+                }
+                else
+                {
+                    /* Otherwise just return the object pointer */
+                    hMem = &HandleEntry->Object;
+                }
             }
+            else
+            {
+                /* Otherwise, we're allocating, so set the new flags needed */
+                Flags |= HEAP_SETTABLE_USER_VALUE | GLOBAL_HEAP_FLAG_MOVABLE;
+                if (!Ptr)
+                {
+                    /* We don't have a base, so allocate one */
+                    Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
+                    BASE_TRACE_ALLOC2(Ptr);
+                    if (Ptr)
+                    {
+                        /* Allocation succeeded, so save our entry */
+                        RtlSetUserValueHeap(hProcessHeap,
+                                            HEAP_NO_SERIALIZE,
+                                            Ptr,
+                                            hMem);
+                    }
+                }
+                else
+                {
+                    /*
+                     * If it's not movable or currently locked, we MUST allocate
+                     * in-place!
+                     */
+                    if (!(uFlags & GMEM_MOVEABLE) && (HandleEntry->LockCount))
+                    {
+                        /* Set the flag */
+                        Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
+                    }
+                    else
+                    {
+                        /* Otherwise clear the flag if we set it previously */
+                        Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
+                    }
+
+                    /* And do the re-allocation */
+                    Ptr = RtlReAllocateHeap(hProcessHeap, Flags, Ptr, dwBytes);
+                }
 
-            /* reallocate fixed memory */
-            hnew = (HANDLE)RtlReAllocateHeap(GetProcessHeap(), heap_flags, (LPVOID) hMem, dwBytes);
+                /* Make sure we have a pointer by now */
+                if (Ptr)
+                {
+                    /* Write it in the handle entry and mark it in use */
+                    HandleEntry->Object = Ptr;
+                    HandleEntry->Flags &= ~GLOBAL_HEAP_ENTRY_FLAG_REUSE;
+                }
+                else
+                {
+                    /* Otherwise we failed */
+                    hMem = NULL;
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                }
+            }
         }
-        else
+    }
+    else if (uFlags & GMEM_MODIFY)
+    {
+        /* This is not a handle-based heap and the caller wants it to be one */
+        if (uFlags & GMEM_MOVEABLE)
         {
-            /* reallocate a moveable block */
-            phandle= HANDLE_TO_INTERN(hMem);
-            hnew = hMem;
-            
-            if (0 != dwBytes)
-            {
-               if(phandle->Pointer)
-               {
-
-                   if (phandle->LockCount && !(uFlags & GMEM_MOVEABLE))
-                   {
-                       /* Locked memory cant normally move but the MEM_MOVEABLE flag
-                        * override this behaviour. But in this case that flag was not passed.
-                        */ 
-                       heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
-                   }
-
-                   palloc = RtlReAllocateHeap(GetProcessHeap(), heap_flags,
-                                      (PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE),
-                                      dwBytes + HANDLE_SIZE);
-                   if (0 == palloc)
-                   {
-                       hnew = 0;
-                   }
-                   else
-                   {
-                       *(PHANDLE)palloc = hMem;
-                       phandle->Pointer = (PVOID)((ULONG_PTR)palloc + HANDLE_SIZE);
-                   }
-               }
-               else
-               {
-                   palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes + HANDLE_SIZE);
-                   if (0 == palloc)
-                   {
-                       hnew = 0;
-                   }
-                   else
-                   {
-                       *(PHANDLE)palloc = hMem;
-                       phandle->Pointer = (PVOID)((ULONG_PTR)palloc + HANDLE_SIZE);
-                   }
-               }
-            }
-            else
+            /* Get information on its current state */
+            Handle = hMem;
+            DPRINT1("h h %lx %lx\n", Handle, hMem);
+            RtlGetUserInfoHeap(hProcessHeap,
+                               HEAP_NO_SERIALIZE,
+                               hMem,
+                               &Handle,
+                               &Flags);
+            DPRINT1("h h %lx %lx\n", Handle, hMem);
+
+            /*
+             * Check if the handle matches the pointer or if the moveable flag
+             * isn't there, which is what we expect since it currenly isn't.
+             */
+            if (Handle == hMem || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
             {
-                if(phandle->Pointer)
+                /* Allocate a handle for it */
+                HandleEntry = GlobalAllocEntry();
+
+                /* Calculate the size of the current heap */
+                dwBytes = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
+
+                /* Set the movable flag */
+                Flags |= HEAP_SETTABLE_USER_VALUE | GLOBAL_HEAP_FLAG_MOVABLE;
+
+                /* Now allocate the actual heap for it */
+                HandleEntry->Object = RtlAllocateHeap(hProcessHeap,
+                                                      Flags,
+                                                      dwBytes);
+                BASE_TRACE_PTR(HandleEntry->Object, HandleEntry);
+                if (!HandleEntry->Object)
                 {
-                    RtlFreeHeap(GetProcessHeap(), 0, (PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE));
-                    phandle->Pointer = 0;
+                    /*
+                     * We failed, manually set the allocate flag and
+                     * free the handle
+                     */
+                    HandleEntry->Flags = RTL_HANDLE_VALID;
+                    GlobalFreeEntry(HandleEntry);
+
+                    /* For the cleanup case */
+                    BASE_TRACE_FAILURE();
+                    HandleEntry = NULL;
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                }
+                else
+                {
+                    /* Otherwise, copy the current heap and free the old one */
+                    RtlMoveMemory(HandleEntry->Object, hMem, dwBytes);
+                    RtlFreeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
+
+                    /* Select the heap pointer */
+                    hMem = (HANDLE)&HandleEntry->Object;
+
+                    /* Initialize the count and default flags */
+                    HandleEntry->LockCount = 0;
+                    HandleEntry->Flags = RTL_HANDLE_VALID |
+                                         GLOBAL_HEAP_ENTRY_FLAG_MOVABLE;
+
+                    /* Check if it's also discardable */
+                    if (uFlags & GMEM_DISCARDABLE)
+                    {
+                        /* Set the internal flag */
+                        HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_REUSABLE;
+                    }
+
+                    /* Check if it's also DDE Shared */
+                    if (uFlags & GMEM_DDESHARE)
+                    {
+                        /* Set the internal flag */
+                        HandleEntry->Flags |= GLOBAL_HEAP_ENTRY_FLAG_DDESHARE;
+                    }
+
+                    /* Allocation succeeded, so save our entry */
+                    RtlSetUserValueHeap(hProcessHeap,
+                                        HEAP_NO_SERIALIZE,
+                                        HandleEntry->Object,
+                                        hMem);
                 }
             }
         }
     }
+    else
+    {
+        /* Otherwise, this is a simple RTL Managed Heap, so just call it */
+        hMem = RtlReAllocateHeap(hProcessHeap,
+                                 Flags | HEAP_NO_SERIALIZE,
+                                 hMem,
+                                 dwBytes);
+        if (!hMem)
+        {
+            /* Fail */
+            BASE_TRACE_FAILURE();
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        }
+    }
 
-    HeapUnlock(GetProcessHeap());
-
-    return hnew;
+    /* All done, unlock the heap and return the pointer */
+    RtlUnlockHeap(hProcessHeap);
+    return hMem;
 }
 
-
-DWORD STDCALL
+/*
+ * @implemented
+ */
+DWORD
+NTAPI
 GlobalSize(HGLOBAL hMem)
 {
-    SIZE_T         retval  = 0;
-    PGLOBAL_HANDLE phandle = 0;
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    PVOID Handle = NULL;
+    ULONG Flags = 0;
+    SIZE_T dwSize = MAXULONG_PTR;
 
-    DPRINT("GlobalSize( 0x%lX )\n", (ULONG)hMem);
+    /* Lock the heap */
+    RtlLockHeap(hProcessHeap);
 
-    if(ISPOINTER(hMem)) /*FIXED*/
+    /* Check if this is a simple RTL Heap Managed block */
+    if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY))
     {
-        retval = RtlSizeHeap(GetProcessHeap(), 0, hMem);
+        /* Then we'll query RTL Heap */
+        RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
+        BASE_TRACE_PTR(Handle, hMem);
+
+        /*
+         * Check if RTL Heap didn't give us a handle or said that this heap
+         * isn't movable.
+         */
+        if (!(Handle) || !(Flags & GLOBAL_HEAP_FLAG_MOVABLE))
+        {
+            /* This implies we're not a handle heap, so use the generic call */
+            dwSize = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
+        }
+        else
+        {
+            /* Otherwise we're a handle heap, so get the internal handle */
+            hMem = Handle;
+        }
     }
-    else /*MOVEABLE*/
-    {
-        HeapLock(GetProcessHeap());
 
-        phandle = HANDLE_TO_INTERN(hMem);
+    /* Make sure that this is an entry in our handle database */
+    if ((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)
+    {
+        /* Get the entry */
+        HandleEntry = GlobalGetEntry(hMem);
+        BASE_TRACE_HANDLE(HandleEntry, hMem);
 
-        if (MAGIC_GLOBAL_USED == phandle->Magic)
+        /* Make sure the handle is valid */
+        if (!GlobalValidateEntry(HandleEntry))
         {
-            if (0 != phandle->Pointer)/*NOT DISCARDED*/
-            {
-                retval = RtlSizeHeap(GetProcessHeap(), 0, (PVOID)((ULONG_PTR)phandle->Pointer - HANDLE_SIZE));
-
-                if (retval == (SIZE_T)-1) /*RtlSizeHeap failed*/
-                {
-                    /*
-                    **TODO: RtlSizeHeap does not set last error.
-                    **      We should choose an error value to set as
-                    **      the last error. Which One?
-                    */
-                    DPRINT("GlobalSize:  RtlSizeHeap failed.\n");
-                    retval = 0;
-                }
-                else /*Everything is ok*/
-                {
-                    retval = retval - HANDLE_SIZE;
-                }
-            }
+            /* Fail */
+            BASE_TRACE_FAILURE();
+            SetLastError(ERROR_INVALID_HANDLE);
+        }
+        else if (HandleEntry->Flags & GLOBAL_HEAP_ENTRY_FLAG_REUSE)
+        {
+            /* We've reused this block, but we've saved the size for you */
+            dwSize = HandleEntry->OldSize;
         }
         else
         {
-            DPRINT("GlobalSize: invalid handle\n");
+            /* Otherwise, query RTL about it */
+            dwSize = RtlSizeHeap(hProcessHeap,
+                                 HEAP_NO_SERIALIZE,
+                                 HandleEntry->Object);
         }
-        HeapUnlock(GetProcessHeap());
     }
-    return retval;
-}
 
+    /* Check if by now, we still haven't gotten any useful size */
+    if (dwSize == MAXULONG_PTR)
+    {
+        /* Fail */
+        BASE_TRACE_FAILURE();
+        SetLastError(ERROR_INVALID_HANDLE);
+        dwSize = 0;
+    }
+
+    /* All done! Unlock heap and return the size */
+    RtlUnlockHeap(hProcessHeap);
+    return dwSize;
+}
 
 /*
  * @implemented
  */
-VOID STDCALL
+VOID
+NTAPI
 GlobalUnfix(HGLOBAL hMem)
 {
-   if (hMem != INVALID_HANDLE_VALUE)
-     GlobalUnlock(hMem);
+    /* If the handle is valid, unlock it */
+    if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem);
 }
 
-
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL
+NTAPI
 GlobalUnlock(HGLOBAL hMem)
 {
+    PGLOBAL_HEAP_HANDLE_ENTRY HandleEntry;
+    BOOL RetVal = TRUE;
 
-   PGLOBAL_HANDLE      phandle;
-   BOOL                            locked = FALSE;
-
-   DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG)hMem);
-
-   if(ISPOINTER(hMem))
-   {
-       SetLastError(ERROR_NOT_LOCKED);
-      return FALSE;
-   }
-
-   HeapLock(GetProcessHeap());
-
-   phandle = HANDLE_TO_INTERN(hMem);
-   if(MAGIC_GLOBAL_USED == phandle->Magic)
-   {
-      if (0 >= phandle->LockCount)
-      {
-          locked = FALSE;
-          SetLastError(ERROR_NOT_LOCKED);
-      }
-      else if (GLOBAL_LOCK_MAX > phandle->LockCount)
-      {
-         phandle->LockCount--;
-         locked = (0 != phandle->LockCount) ? TRUE : FALSE;
-         SetLastError(NO_ERROR);
-      }
-   }
-   else
-   {
-      DPRINT("GlobalUnlock: invalid handle\n");
-      locked = FALSE;
-   }
-   HeapUnlock(GetProcessHeap());
-   return locked;
-}
+    /* Check if this was a simple allocated heap entry */
+    if (!((ULONG_PTR)hMem & GLOBAL_HEAP_IS_HANDLE_ENTRY)) return RetVal;
 
+    /* Otherwise, lock the heap */
+    RtlLockHeap(hProcessHeap);
+
+    /* Get the handle entry */
+    HandleEntry = GlobalGetEntry(hMem);
+    BASE_TRACE_HANDLE(HandleEntry, hMem);
+
+    /* Make sure it's valid */
+    if (!GlobalValidateEntry(HandleEntry))
+    {
+        /* It's not, fail */
+        BASE_TRACE_FAILURE();
+        SetLastError(ERROR_INVALID_HANDLE);
+    }
+    else
+    {
+        /* Otherwise, decrement lock count, unless we're already at 0*/
+        if (!HandleEntry->LockCount--)
+        {
+            /* In which case we simply lock it back and fail */
+            HandleEntry->LockCount++;
+            SetLastError(ERROR_NOT_LOCKED);
+            RetVal = FALSE;
+        }
+        else if (!HandleEntry->LockCount)
+        {
+            /* Nothing to unlock */
+            SetLastError(NO_ERROR);
+            RetVal = FALSE;
+        }
+    }
+
+    /* All done. Unlock the heap and return the pointer */
+    RtlUnlockHeap(hProcessHeap);
+    return RetVal;
+}
 
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL
+NTAPI
 GlobalUnWire(HGLOBAL hMem)
 {
-   return GlobalUnlock(hMem);
+    /* This is simply an unlock */
+    return GlobalUnlock(hMem);
 }
 
-
 /*
  * @implemented
  */
-LPVOID STDCALL
+LPVOID
+NTAPI
 GlobalWire(HGLOBAL hMem)
 {
-   return GlobalLock(hMem);
+    /* This is just a lock */
+    return GlobalLock(hMem);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+NTAPI
+GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
+{
+    SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
+    VM_COUNTERS VmCounters;
+    QUOTA_LIMITS QuotaLimits;
+    ULONGLONG PageFile, PhysicalMemory;
+
+    /* Query performance information */
+    NtQuerySystemInformation(SystemPerformanceInformation,
+                             &PerformanceInfo,
+                             sizeof(PerformanceInfo),
+                             NULL);
+
+    /* Calculate memory load */
+    lpBuffer->dwMemoryLoad = ((DWORD)(BaseCachedSysInfo.NumberOfPhysicalPages -
+                                      PerformanceInfo.AvailablePages) * 100) /
+                                      BaseCachedSysInfo.NumberOfPhysicalPages;
+
+    /* Save physical memory */
+    PhysicalMemory = BaseCachedSysInfo.NumberOfPhysicalPages *
+                     BaseCachedSysInfo.PageSize;
+    lpBuffer->ullTotalPhys = PhysicalMemory;
+
+    /* Now save available physical memory */
+    PhysicalMemory = PerformanceInfo.AvailablePages *
+                     BaseCachedSysInfo.PageSize;
+    lpBuffer->ullAvailPhys = PhysicalMemory;
+
+    /* Query VM and Quota Limits */
+    NtQueryInformationProcess(NtCurrentProcess(),
+                              ProcessQuotaLimits,
+                              &QuotaLimits,
+                              sizeof(QUOTA_LIMITS),
+                              NULL);
+    NtQueryInformationProcess(NtCurrentProcess(),
+                              ProcessVmCounters,
+                              &VmCounters,
+                              sizeof(VM_COUNTERS),
+                              NULL);
+
+    /* Save the commit limit */
+    lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
+                                     PerformanceInfo.CommitLimit);
+
+    /* Calculate how many pages are left */
+    PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
+
+    /* Save the total */
+    lpBuffer->ullAvailPageFile = min(PageFile,
+                                     QuotaLimits.PagefileLimit -
+                                     VmCounters.PagefileUsage);
+    lpBuffer->ullAvailPageFile *= BaseCachedSysInfo.PageSize;
+
+    /* Now calculate the total virtual space */
+    lpBuffer->ullTotalVirtual = (BaseCachedSysInfo.MaximumUserModeAddress -
+                                 BaseCachedSysInfo.MinimumUserModeAddress) + 1;
+
+    /* And finally the avilable virtual space */
+    lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual -
+                                VmCounters.VirtualSize;
+    lpBuffer->ullAvailExtendedVirtual = 0;
+    return TRUE;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
+{
+    MEMORYSTATUSEX lpBufferEx;
+
+    /* Call the extended function */
+    lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
+    if (GlobalMemoryStatusEx(&lpBufferEx))
+    {
+        /* Reset the right size and fill out the information */
+        lpBuffer->dwLength = sizeof(MEMORYSTATUS);
+        lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
+        lpBuffer->dwTotalPhys = lpBufferEx.ullTotalPhys;
+        lpBuffer->dwAvailPhys = lpBufferEx.ullAvailPhys;
+        lpBuffer->dwTotalPageFile = lpBufferEx.ullTotalPageFile;
+        lpBuffer->dwAvailPageFile = lpBufferEx.ullAvailPageFile;
+        lpBuffer->dwTotalVirtual = lpBufferEx.ullTotalVirtual;
+        lpBuffer->dwAvailVirtual = lpBufferEx.ullAvailVirtual;
+    }
 }
 
 /* EOF */
index 97018bf..2b30939 100644 (file)
@@ -339,6 +339,9 @@ DllMain(HANDLE hDll,
         }
 
         hProcessHeap = RtlGetProcessHeap();
+        RtlInitializeHandleTable(0xFFFF,
+                                 sizeof(GLOBAL_HEAP_HANDLE_ENTRY),
+                                 &BaseGlobalHandleTable);
         hCurrentModule = hDll;
         DPRINT("Heap: %p\n", hProcessHeap);