Minor fix in GlobalMemoryStatus to get some applications happy.
[reactos.git] / reactos / lib / kernel32 / mem / global.c
index 45e12ee..3c4eb0f 100644 (file)
-/* $Id: global.c,v 1.4 2000/07/01 17:07:00 ea Exp $
+/* $Id: global.c,v 1.19 2004/01/21 18:57:21 navaraf Exp $
  *
  * 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.
  */
 
-#include <windows.h>
+#include <k32.h>
+#include <time.h>
 
 #define NDEBUG
 #include <kernel32/kernel32.h>
 
+#ifdef _GNUC_
+#define STRUCT_PACK __attribute__((packed))
+#else
+#define STRUCT_PACK
+#endif
+
 #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
 {
-   ULONG       Magic;
-   LPVOID      Pointer;
-   BYTE                Flags;
-   BYTE                LockCount;
+    DWORD   Magic;
+    LPVOID  Pointer; STRUCT_PACK
+    BYTE    Flags;
+    BYTE    LockCount;
 } GLOBAL_HANDLE, LOCAL_HANDLE, *PGLOBAL_HANDLE, *PLOCAL_HANDLE;
 
-/*********************************************************************
-*                    GlobalAlloc  --  KERNEL32                       *
-*********************************************************************/
-HGLOBAL WINAPI GlobalAlloc(UINT flags, DWORD size)
+#define HANDLE_TO_INTERN(h)  ((PGLOBAL_HANDLE)(((char *)(h))-4))
+#define INTERN_TO_HANDLE(i)  ((HGLOBAL) &((i)->Pointer))
+#define POINTER_TO_HANDLE(p) (*(PHANDLE)(p - HANDLE_SIZE))
+#define ISHANDLE(h)          ((((ULONG)(h)) & 0x4)!=0)
+#define ISPOINTER(h)         ((((ULONG)(h)) & 0x4)==0)
+
+
+static void DbgPrintStruct(PGLOBAL_HANDLE h)
 {
-   PGLOBAL_HANDLE      phandle;
-   LPVOID              palloc;
+    DbgPrint("Magic:     0x%X\n", h->Magic);
+    DbgPrint("Pointer:   0x%X\n", h->Pointer);
+    DbgPrint("Flags:     0x%X\n", h->Flags);
+    DbgPrint("LockCount: 0x%X\n", h->LockCount);
+}
 
-   DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", flags, size );
 
-   if((flags & GMEM_MOVEABLE)==0) /* POINTER */
-   {
-      palloc=HeapAlloc(__ProcessHeap, 0, size);
-      return (HGLOBAL) palloc;
-   }
-   else  /* HANDLE */
-   {
-      HeapLock(__ProcessHeap);
 
+/* FUNCTIONS ***************************************************************/
 
-      phandle=__HeapAllocFragment(__ProcessHeap, 0,  sizeof(GLOBAL_HANDLE));
-      if(size)
-      {
-         palloc=HeapAlloc(__ProcessHeap, 0, size+sizeof(HANDLE));
-         *(PHANDLE)palloc=(HANDLE) &(phandle->Pointer);
-         phandle->Pointer=palloc+sizeof(HANDLE);
-      }
-      else
-         phandle->Pointer=NULL;
-      phandle->Magic=MAGIC_GLOBAL_USED;
-      phandle->Flags=flags>>8;
-      phandle->LockCount=0;
-      HeapUnlock(__ProcessHeap);
-
-      return (HGLOBAL) &(phandle->Pointer);
-   }
+/*
+ * @implemented
+ */
+HGLOBAL STDCALL
+GlobalAlloc(UINT uFlags,
+            DWORD dwBytes)
+{
+
+    PGLOBAL_HANDLE phandle    = 0;
+    PVOID          palloc     = 0;
+    UINT           heap_flags = 0;
+    /*Fixme: When we are sure all allocations are 8-byte aligned,
+    **we can remove this hack.
+    */
+    PGLOBAL_HANDLE hack_fix   = 0;
+
+    if (uFlags & GMEM_ZEROINIT)
+    {
+        heap_flags = HEAP_ZERO_MEMORY;
+    }
+
+    DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", uFlags, dwBytes);
+    
+    //Changed hProcessHeap to GetProcessHeap()
+    if ((uFlags & GMEM_MOVEABLE)==0) /* POINTER */
+    {
+        return ((HGLOBAL)RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes));
+    }
+    else  /* HANDLE */
+    {
+        HeapLock(hProcessHeap);
+
+        phandle = RtlAllocateHeap(GetProcessHeap(), 0,  sizeof(GLOBAL_HANDLE));
+        /* This little hack is to make sure that we get a pointer with 8-byte
+        ** alignment.
+        ** Fixme: When we are sure all allocations are 8-byte aligned,
+        ** we can remove this hack.
+        */
+        if (ISPOINTER(INTERN_TO_HANDLE(phandle)))
+        {
+            hack_fix = RtlAllocateHeap(GetProcessHeap(), 0,  sizeof(GLOBAL_HANDLE));
+            RtlFreeHeap(GetProcessHeap(), 0, phandle);
+            phandle = hack_fix;
+        }
+        if (phandle)
+        {
+            phandle->Magic     = MAGIC_GLOBAL_USED;
+            phandle->Flags     = uFlags >> 8;
+            phandle->LockCount = 0;
+            phandle->Pointer   = 0;
+
+            if (dwBytes)
+            {
+                palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes + HANDLE_SIZE);
+                if (palloc)
+                {
+                    *(PHANDLE)palloc = INTERN_TO_HANDLE(phandle);
+                    phandle->Pointer = palloc + HANDLE_SIZE;
+                }
+                else /*failed to allocate the memory block*/
+                {
+                    RtlFreeHeap(GetProcessHeap(), 0, phandle);
+                    phandle = 0;
+                }
+            }
+            else
+            {
+                DbgPrint("Allocated a 0 size movable block.\n");
+                DbgPrintStruct(phandle);
+                DbgPrint("Address of the struct: 0x%X\n", phandle);
+                DbgPrint("Address of pointer:    0x%X\n", &(phandle->Pointer));
+            }
+        }
+        HeapUnlock(hProcessHeap);
+
+        if (phandle)
+            return INTERN_TO_HANDLE(phandle);  
+        else
+            return (HGLOBAL)0;
+    }
 }
 
-/*********************************************************************
-*                    GlobalLock  --  KERNEL32                        *
-*********************************************************************/
-LPVOID WINAPI GlobalLock(HGLOBAL hmem)
-{
-   PGLOBAL_HANDLE phandle;
-   LPVOID         palloc;
 
-   DPRINT("GlobalLock( 0x%lX )\n", (ULONG) hmem );
+/*
+ * @implemented
+ */
+UINT STDCALL
+GlobalCompact(DWORD dwMinFree)
+{
+   return RtlCompactHeap(hProcessHeap, 0);
+}
 
-   if(((ULONG)hmem%8)==0)
-      return (LPVOID) hmem;
 
-   HeapLock(__ProcessHeap);
-   phandle=(PGLOBAL_HANDLE)(((LPVOID) hmem)-4);
-   if(phandle->Magic==MAGIC_GLOBAL_USED)
-   {
-      if(phandle->LockCount<GLOBAL_LOCK_MAX)
-         phandle->LockCount++;
-      palloc=phandle->Pointer;
-   }
-   else
-   {
-      DPRINT("GlobalLock: invalid handle\n");
-      palloc=(LPVOID) hmem;
-   }
-   HeapUnlock(__ProcessHeap);
-   return palloc;
+/*
+ * @implemented
+ */
+VOID STDCALL
+GlobalFix(HGLOBAL hMem)
+{
+   if (INVALID_HANDLE_VALUE != hMem)
+     GlobalLock(hMem);
 }
 
-/*********************************************************************
-*                    GlobalUnlock  --  KERNEL32                      *
-*********************************************************************/
-BOOL WINAPI GlobalUnlock(HGLOBAL hmem)
+/*
+ * @implemented
+ */
+UINT STDCALL
+GlobalFlags(HGLOBAL hMem)
 {
-   PGLOBAL_HANDLE      phandle;
-   BOOL                        locked;
+    DWORD                  retval;
+    PGLOBAL_HANDLE     phandle;
+
+    DbgPrint("GlobalFlags( 0x%lX )\n", (ULONG)hMem);
+
+    if(!ISHANDLE(hMem))
+    {
+        DbgPrint("GlobalFlags: Fixed memory.\n");
+        retval = 0;
+    }
+    else
+    {
+        HeapLock(GetProcessHeap());
+        
+        phandle = HANDLE_TO_INTERN(hMem);
+
+        /*DbgPrintStruct(phandle);*/
+
+        if (MAGIC_GLOBAL_USED == phandle->Magic)
+        {
+            /*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;
+            }
+        }
+        else
+        {
+            DbgPrint("GlobalSize: invalid handle\n");
+            retval = 0;
+        }
+        HeapUnlock(GetProcessHeap());
+    }
+    return retval;
+}
 
-   DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG) hmem );
 
-   if(((ULONG)hmem%8)==0)
-      return FALSE;
+/*
+ * @implemented
+ */
+HGLOBAL STDCALL
+GlobalFree(HGLOBAL hMem)
+{
+    PGLOBAL_HANDLE phandle;
+    
+    DPRINT("GlobalFree( 0x%lX )\n", (ULONG)hMem);
+
+    if (ISPOINTER(hMem)) /* POINTER */
+    {
+        RtlFreeHeap(GetProcessHeap(), 0, (PVOID)hMem);
+        hMem = 0;
+    }
+    else /* HANDLE */
+    {
+        HeapLock(GetProcessHeap());
+        
+        phandle = HANDLE_TO_INTERN(hMem);
+
+        if(MAGIC_GLOBAL_USED == phandle->Magic)
+        {
+
+            if(phandle->LockCount!=0)
+            {
+                DbgPrint("Warning! GlobalFree(0x%X) Freeing a handle to a locked object.\n", hMem);
+                SetLastError(ERROR_INVALID_HANDLE);
+            }
+            
+            if(phandle->Pointer)
+                RtlFreeHeap(GetProcessHeap(), 0, phandle->Pointer - HANDLE_SIZE);
+            
+            RtlFreeHeap(GetProcessHeap(), 0, phandle);
+        }
+        HeapUnlock(GetProcessHeap());
+        
+        hMem = 0;
+    }
+    return hMem;
+}
 
-   HeapLock(__ProcessHeap);
-   phandle=(PGLOBAL_HANDLE)(((LPVOID) hmem)-4);
-   if(phandle->Magic==MAGIC_GLOBAL_USED)
-   {
-      if((phandle->LockCount<GLOBAL_LOCK_MAX)&&(phandle->LockCount>0))
-         phandle->LockCount--;
 
-      locked=(phandle->LockCount==0) ? TRUE : FALSE;
-   }
-   else
-   {
-      DPRINT("GlobalUnlock: invalid handle\n");
-      locked=FALSE;
-   }
-   HeapUnlock(__ProcessHeap);
-   return locked;
+/*
+ * @implemented
+ */
+HGLOBAL STDCALL
+GlobalHandle(LPCVOID pMem)
+{
+    HGLOBAL              handle = 0;
+    PGLOBAL_HANDLE         test = 0;
+    LPCVOID        pointer_test = 0;
+
+    DbgPrint("GlobalHandle( 0x%lX )\n", (ULONG)pMem);
+    if (0 == pMem) /*Invalid argument */
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        DbgPrint("Error: 0 handle.\n");
+        return 0;
+    }
+  
+    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*/
+    {
+        handle = POINTER_TO_HANDLE(pMem);        
+    }
+    
+     
+    /* Test to see if this memory is valid*/
+    test  = HANDLE_TO_INTERN(handle);
+    if (!IsBadReadPtr(test, sizeof(GLOBAL_HANDLE)))
+    {
+        if (MAGIC_GLOBAL_USED == test->Magic)
+        {
+            pointer_test = test->Pointer;
+            if (!RtlValidateHeap(GetProcessHeap(), 0, ((char *)pointer_test) - HANDLE_SIZE) ||
+                !RtlValidateHeap(GetProcessHeap(), 0, test))
+            {
+                SetLastError(ERROR_INVALID_HANDLE);
+                handle = 0;
+            }
+        }
+    }
+    else
+    {
+        DbgPrint("GlobalHandle: Bad read pointer.\n");
+        SetLastError(ERROR_INVALID_HANDLE);
+        handle = 0;
+    }
+
+    HeapUnlock(GetProcessHeap());
+
+    return handle;
 }
 
-/*********************************************************************
-*                    GlobalHandle  --  KERNEL32                      *
-*********************************************************************/
-HGLOBAL WINAPI GlobalHandle(LPCVOID pmem)
-{
-   DPRINT("GlobalHandle( 0x%lX )\n", (ULONG) pmem );
 
-   if(((ULONG)pmem%8)==0) /* FIXED */
-      return (HGLOBAL) pmem;
-   else  /* MOVEABLE */
-      return (HGLOBAL) *(LPVOID *)(pmem-sizeof(HANDLE));
+/*
+ * @implemented
+ */
+LPVOID STDCALL
+GlobalLock(HGLOBAL hMem)
+{
+    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)
+    {
+        if(GLOBAL_LOCK_MAX > phandle->LockCount)
+        {
+            phandle->LockCount++;
+        }
+        palloc = phandle->Pointer;
+    }
+    else
+    {
+        DPRINT("GlobalLock: invalid handle\n");
+        palloc = (LPVOID) hMem;
+    }
+
+    HeapUnlock(GetProcessHeap());
+    
+    return palloc;
 }
 
-/*********************************************************************
-*                    GlobalReAlloc  --  KERNEL32                     *
-*********************************************************************/
-HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hmem, DWORD size, UINT flags)
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
 {
-   LPVOID              palloc;
-   HGLOBAL             hnew;
-   PGLOBAL_HANDLE      phandle;
+    static MEMORYSTATUS        cached_memstatus;
+//    static int cache_lastchecked = 0;
+    SYSTEM_INFO si;
+
+//    if (GetSystemTimeAsFileTime(NULL)==cache_lastchecked) {
+//     memcpy(lpBuffer,&cached_memstatus,sizeof(MEMORYSTATUS));
+//     return;
+//    }
+//    cache_lastchecked = GetSystemTimeAsFileTime(NULL);
+
+    lpBuffer->dwLength        = sizeof(MEMORYSTATUS);
+    lpBuffer->dwMemoryLoad    = 0;
+    lpBuffer->dwTotalPhys     = 32*1024*1024;
+    lpBuffer->dwAvailPhys     = 32*1024*1024;
+    lpBuffer->dwTotalPageFile = 32*1024*1024;
+    lpBuffer->dwAvailPageFile = 32*1024*1024;
+
+    /* Some applications (e.g. QuickTime 6) crash if we tell them there
+     * is more than 2GB of physical memory.
+     */
+    if (lpBuffer->dwTotalPhys>2U*1024*1024*1024)
+    {
+        lpBuffer->dwTotalPhys=2U*1024*1024*1024;
+        lpBuffer->dwAvailPhys=2U*1024*1024*1024;
+    }
+
+    /* FIXME: should do something for other systems */
+    GetSystemInfo(&si);
+    lpBuffer->dwTotalVirtual  = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
+    /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
+    lpBuffer->dwAvailVirtual  = lpBuffer->dwTotalVirtual-64*1024;
+    memcpy(&cached_memstatus,lpBuffer,sizeof(MEMORYSTATUS));
+
+    /* it appears some memory display programs want to divide by these values */
+    if(lpBuffer->dwTotalPageFile==0)
+        lpBuffer->dwTotalPageFile++;
+
+    if(lpBuffer->dwAvailPageFile==0)
+        lpBuffer->dwAvailPageFile++;
+
+    DPRINT1("<-- LPMEMORYSTATUS: dwLength %ld, dwMemoryLoad %ld, dwTotalPhys %ld, dwAvailPhys %ld,"
+          " dwTotalPageFile %ld, dwAvailPageFile %ld, dwTotalVirtual %ld, dwAvailVirtual %ld\n",
+          lpBuffer->dwLength, lpBuffer->dwMemoryLoad, lpBuffer->dwTotalPhys, lpBuffer->dwAvailPhys,
+          lpBuffer->dwTotalPageFile, lpBuffer->dwAvailPageFile, lpBuffer->dwTotalVirtual,
+          lpBuffer->dwAvailVirtual);
+}
 
-   DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG) hmem, size, flags );
 
-   hnew=NULL;
-   HeapLock(__ProcessHeap);
-   if(flags & GMEM_MODIFY) /* modify flags */
-   {
-      if( (((ULONG)hmem%8)==0) && (flags & GMEM_MOVEABLE))
-      {
-         /* make a fixed block moveable
-          * actually only NT is able to do this. And it's soo simple
-          */
-         size=HeapSize(__ProcessHeap, 0, (LPVOID) hmem);
-         hnew=GlobalAlloc( flags, size);
-         palloc=GlobalLock(hnew);
-         memcpy(palloc, (LPVOID) hmem, size);
-         GlobalUnlock(hnew);
-         GlobalHeapFree(GetProcessHeap(),0,hmem);
-      }
-      else if((((ULONG)hmem%8) != 0)&&(flags & GMEM_DISCARDABLE))
-      {
-         /* change the flags to make our block "discardable" */
-         phandle=(PGLOBAL_HANDLE)(((LPVOID) hmem)-4);
-         phandle->Flags = phandle->Flags | (GMEM_DISCARDABLE >> 8);
-         hnew=hmem;
-      }
-      else
-      {
-         SetLastError(ERROR_INVALID_PARAMETER);
-         hnew=NULL;
-      }
-   }
-   else
-   {
-      if(((ULONG)hmem%8)!=0)
-      {
-         /* reallocate fixed memory */
-         hnew=(HANDLE)HeapReAlloc(__ProcessHeap, 0, (LPVOID) hmem, size);
-      }
-      else
-      {
-         /* reallocate a moveable block */
-         phandle=(PGLOBAL_HANDLE)(((LPVOID) hmem)-4);
-         if(phandle->LockCount!=0)
-            SetLastError(ERROR_INVALID_HANDLE);
-         else if(size!=0)
-         {
-            hnew=hmem;
-            if(phandle->Pointer)
+HGLOBAL STDCALL
+GlobalReAlloc(HGLOBAL hMem,
+             DWORD dwBytes,
+             UINT uFlags)
+{
+
+    LPVOID         palloc = 0;
+    HGLOBAL        hnew = 0;
+    PGLOBAL_HANDLE phandle = 0;
+    ULONG          heap_flags = 0;
+
+    DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG)hMem, dwBytes, uFlags);
+
+    hnew = 0;
+    
+    if (uFlags & GMEM_ZEROINIT)
+    {
+        heap_flags = HEAP_ZERO_MEMORY;
+    }
+
+    HeapLock(GetProcessHeap());
+    
+    if(uFlags & GMEM_MODIFY) /* modify flags */
+    {
+        if( ISPOINTER(hMem) && (uFlags & GMEM_MOVEABLE))
+        {
+            /* make a fixed block moveable
+            * actually only NT is able to do this. And it's soo simple
+            */
+            if (0 == hMem)
             {
-               palloc=HeapReAlloc(__ProcessHeap, 0,
-                                  phandle->Pointer-sizeof(HANDLE),
-                                  size+sizeof(HANDLE) );
-               phandle->Pointer=palloc+sizeof(HANDLE);
+                SetLastError( ERROR_NOACCESS );
+                hnew = 0;
             }
             else
             {
-               palloc=HeapAlloc(__ProcessHeap, 0, size+sizeof(HANDLE));
-               *(PHANDLE)palloc=hmem;
-               phandle->Pointer=palloc+sizeof(HANDLE);
+                dwBytes   = RtlSizeHeap(GetProcessHeap(), 0, (LPVOID) hMem);
+                hnew      = GlobalAlloc( uFlags, dwBytes);
+                palloc    = GlobalLock(hnew);
+                memcpy(palloc, (LPVOID) hMem, dwBytes);
+                GlobalUnlock(hnew);
+                RtlFreeHeap(GetProcessHeap(),0,hMem);
             }
-         }
-         else
-         {
-            if(phandle->Pointer)
+        }
+        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))
+        {
+            /* reallocate fixed memory */
+            hnew = (HANDLE)RtlReAllocateHeap(GetProcessHeap(), heap_flags, (LPVOID) hMem, dwBytes);
+        }
+        else
+        {
+            /* reallocate a moveable block */
+            phandle= HANDLE_TO_INTERN(hMem);
+#if 0
+            if(phandle->LockCount != 0)
             {
-               HeapHeapFree(GetProcessHeap(),0,__ProcessHeap, 0, phandle->Pointer-sizeof(HANDLE));
-               phandle->Pointer=NULL;
+                SetLastError(ERROR_INVALID_HANDLE);
             }
-         }
-      }
-   }
-   HeapUnlock(__ProcessHeap);
-   return hnew;
+            else
+#endif
+            if (0 != dwBytes)
+            {
+                hnew = hMem;
+                if(phandle->Pointer)
+                {
+                    palloc = RtlReAllocateHeap(GetProcessHeap(), heap_flags,
+                                         phandle->Pointer - HANDLE_SIZE,
+                                         dwBytes + HANDLE_SIZE);
+                    if (0 == palloc)
+                    {
+                        hnew = 0;
+                    }
+                    else
+                    {
+                        *(PHANDLE)palloc = hMem;
+                        phandle->Pointer = palloc + HANDLE_SIZE;
+                    }
+                }
+                else
+                {
+                    palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes + HANDLE_SIZE);
+                    if (0 == palloc)
+                    {
+                        hnew = 0;
+                    }
+                    else
+                    {
+                        *(PHANDLE)palloc = hMem;
+                        phandle->Pointer = palloc + HANDLE_SIZE;
+                    }
+                }
+            }
+            else
+            {
+                hnew = hMem;
+                if(phandle->Pointer)
+                {
+                    RtlFreeHeap(GetProcessHeap(), 0, phandle->Pointer - HANDLE_SIZE);
+                    phandle->Pointer = 0;
+                }
+            }
+        }
+    }
+    HeapUnlock(GetProcessHeap());
+   
+    return hnew;
 }
 
-/*********************************************************************
-*                    GlobalFree  --  KERNEL32                        *
-*********************************************************************/
-HGLOBAL WINAPI GlobalHeapFree(GetProcessHeap(),0,HGLOBAL hmem)
+
+DWORD STDCALL
+GlobalSize(HGLOBAL hMem)
 {
-   PGLOBAL_HANDLE phandle;
+    SIZE_T         retval  = 0;
+    PGLOBAL_HANDLE phandle = 0;
+    
+    DbgPrint("GlobalSize( 0x%lX )\n", (ULONG)hMem);
+    
+    if(ISPOINTER(hMem)) /*FIXED*/
+    {
+        retval = RtlSizeHeap(GetProcessHeap(), 0, hMem);
+    }
+    else /*MOVEABLE*/
+    {
+        HeapLock(GetProcessHeap());
+        
+        phandle = HANDLE_TO_INTERN(hMem);
+        
+        if (MAGIC_GLOBAL_USED == phandle->Magic)
+        {
+            if (0 != phandle->Pointer)/*NOT DISCARDED*/
+            {
+                retval = RtlSizeHeap(GetProcessHeap(), 0, 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?
+                    */
+                    DbgPrint("GlobalSize:  RtlSizeHeap failed.\n");
+                    retval = 0;
+                }
+                else /*Everything is ok*/
+                {
+                    retval = retval - HANDLE_SIZE;
+                }
+            }
+        }
+        else
+        {
+            DPRINT("GlobalSize: invalid handle\n");
+        }
+        HeapUnlock(GetProcessHeap());
+    }
+    return retval;
+}
 
-   DPRINT("GlobalHeapFree(GetProcessHeap(),0, 0x%lX )\n", (ULONG) hmem );
 
-   if(((ULONG)hmem%4)==0) /* POINTER */
-   {
-      HeapHeapFree(GetProcessHeap(),0,__ProcessHeap, 0, (LPVOID) hmem);
-   }
-   else  /* HANDLE */
-   {
-      HeapLock(__ProcessHeap);
-      phandle=(PGLOBAL_HANDLE)(((LPVOID) hmem)-4);
-      if(phandle->Magic==MAGIC_GLOBAL_USED)
-      {
-         HeapLock(__ProcessHeap);
-         if(phandle->LockCount!=0)
-            SetLastError(ERROR_INVALID_HANDLE);
-         if(phandle->Pointer)
-            HeapHeapFree(GetProcessHeap(),0,__ProcessHeap, 0, phandle->Pointer-sizeof(HANDLE));
-         __HeapFreeFragment(__ProcessHeap, 0, phandle);
-      }
-      HeapUnlock(__ProcessHeap);
-   }
-   return hmem;
+/*
+ * @implemented
+ */
+VOID STDCALL
+GlobalUnfix(HGLOBAL hMem)
+{
+   if (hMem != INVALID_HANDLE_VALUE)
+     GlobalUnlock(hMem);
 }
 
-/*********************************************************************
-*                    GlobalSize  --  KERNEL32                        *
-*********************************************************************/
-DWORD WINAPI GlobalSize(HGLOBAL hmem)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GlobalUnlock(HGLOBAL hMem)
 {
-   DWORD               retval;
+
    PGLOBAL_HANDLE      phandle;
+   BOOL                            locked;
 
-   DPRINT("GlobalSize( 0x%lX )\n", (ULONG) hmem );
+   DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG)hMem);
 
-   if(((ULONG)hmem%8)==0)
+   if(ISPOINTER(hMem))
    {
-      retval=HeapSize(__ProcessHeap, 0,  hmem);
+       SetLastError(ERROR_NOT_LOCKED);
+      return FALSE;
    }
-   else
+
+   HeapLock(GetProcessHeap());
+
+   phandle = HANDLE_TO_INTERN(hMem);
+   if(MAGIC_GLOBAL_USED == phandle->Magic)
    {
-      HeapLock(__ProcessHeap);
-      phandle=(PGLOBAL_HANDLE)(((LPVOID) hmem)-4);
-      if(phandle->Magic==MAGIC_GLOBAL_USED)
+      if (0 >= phandle->LockCount)
       {
-         retval=HeapSize(__ProcessHeap, 0, (phandle->Pointer)-sizeof(HANDLE))-4;
+          locked = FALSE;
+          SetLastError(ERROR_NOT_LOCKED);
       }
-      else
+      else if (GLOBAL_LOCK_MAX > phandle->LockCount)
       {
-         DPRINT("GlobalSize: invalid handle\n");
-         retval=0;
+         phandle->LockCount--;
+         locked = (0 == phandle->LockCount) ? TRUE : FALSE;
+         SetLastError(NO_ERROR);
       }
-      HeapUnlock(__ProcessHeap);
    }
-   return retval;
+   else
+   {
+      DPRINT("GlobalUnlock: invalid handle\n");
+      locked = FALSE;
+   }
+   HeapUnlock(GetProcessHeap());
+   return locked;
 }
 
-/*********************************************************************
-*                    GlobalWire  --  KERNEL32                        *
-*********************************************************************/
-LPVOID WINAPI GlobalWire(HGLOBAL hmem)
-{
-   return GlobalLock( hmem );
-}
 
-/*********************************************************************
-*                    GlobalUnWire  --  KERNEL32                      *
-*********************************************************************/
-BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
-{
-   return GlobalUnlock( hmem);
-}
-
-/*********************************************************************
-*                    GlobalFix  --  KERNEL32                         *
-*********************************************************************/
-VOID WINAPI GlobalFix(HGLOBAL hmem)
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GlobalUnWire(HGLOBAL hMem)
 {
-   GlobalLock( hmem );
+   return GlobalUnlock(hMem);
 }
 
-/*********************************************************************
-*                    GlobalUnfix  --  KERNEL32                       *
-*********************************************************************/
-VOID WINAPI GlobalUnfix(HGLOBAL hmem)
-{
-   GlobalUnlock( hmem);
-}
 
-/*********************************************************************
-*                    GlobalFlags  --  KERNEL32                       *
-*********************************************************************/
-UINT WINAPI GlobalFlags(HGLOBAL hmem)
+/*
+ * @implemented
+ */
+LPVOID STDCALL
+GlobalWire(HGLOBAL hMem)
 {
-   return LocalFlags( (HLOCAL) hmem);
+   return GlobalLock(hMem);
 }
 
+/*
+ * @implemented
+ */
+//HGLOBAL STDCALL
+//GlobalDiscard(HGLOBAL hMem)
+//{
+//    return GlobalReAlloc(hMem, 0, GMEM_MOVEABLE);
+//}
 /* EOF */