Removed some unnecessary inclusions of thread.h
[wine] / dlls / kernel / heap.c
1 /*
2  * Win32 heap functions
3  *
4  * Copyright 1995, 1996 Alexandre Julliard
5  * Copyright 1996 Huw Davies
6  * Copyright 1998 Ulrich Weigand
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <time.h>
33 #ifdef HAVE_SYS_PARAM_H
34 #include <sys/param.h>
35 #endif
36 #ifdef HAVE_SYS_SYSCTL_H
37 #include <sys/sysctl.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winerror.h"
46 #include "winnt.h"
47 #include "winreg.h"
48 #include "winternl.h"
49 #include "excpt.h"
50 #include "wine/exception.h"
51 #include "wine/debug.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(heap);
54
55 /* address where we try to map the system heap */
56 #define SYSTEM_HEAP_BASE  ((void*)0x80000000)
57 #define SYSTEM_HEAP_SIZE  0x1000000   /* Default heap size = 16Mb */
58
59 static HANDLE systemHeap;   /* globally shared heap */
60
61
62
63 /* filter for page-fault exceptions */
64 /* It is possible for a bogus global pointer to cause a */
65 /* page zero reference, so I include EXCEPTION_PRIV_INSTRUCTION too. */
66 static WINE_EXCEPTION_FILTER(page_fault)
67 {
68     switch (GetExceptionCode()) {
69         case (EXCEPTION_ACCESS_VIOLATION):
70         case (EXCEPTION_PRIV_INSTRUCTION):
71            return EXCEPTION_EXECUTE_HANDLER;
72         default:
73            return EXCEPTION_CONTINUE_SEARCH;
74     }
75 }
76
77 /***********************************************************************
78  *           HEAP_CreateSystemHeap
79  *
80  * Create the system heap.
81  */
82 inline static HANDLE HEAP_CreateSystemHeap(void)
83 {
84     int created;
85     void *base;
86     HANDLE map, event;
87
88     /* create the system heap event first */
89     event = CreateEventA( NULL, TRUE, FALSE, "__wine_system_heap_event" );
90
91     if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
92                                     0, SYSTEM_HEAP_SIZE, "__wine_system_heap" ))) return 0;
93     created = (GetLastError() != ERROR_ALREADY_EXISTS);
94
95     if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
96     {
97         /* pre-defined address not available */
98         ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
99         return 0;
100     }
101
102     if (created)  /* newly created heap */
103     {
104         systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
105                                     SYSTEM_HEAP_SIZE, NULL, NULL );
106         SetEvent( event );
107     }
108     else
109     {
110         /* wait for the heap to be initialized */
111         WaitForSingleObject( event, INFINITE );
112         systemHeap = (HANDLE)base;
113     }
114     CloseHandle( map );
115     return systemHeap;
116 }
117
118
119 /***********************************************************************
120  *           HeapCreate   (KERNEL32.@)
121  * RETURNS
122  *      Handle of heap: Success
123  *      NULL: Failure
124  */
125 HANDLE WINAPI HeapCreate(
126                 DWORD flags,       /* [in] Heap allocation flag */
127                 SIZE_T initialSize, /* [in] Initial heap size */
128                 SIZE_T maxSize      /* [in] Maximum heap size */
129 ) {
130     HANDLE ret;
131
132     if ( flags & HEAP_SHARED )
133     {
134         if (!systemHeap) HEAP_CreateSystemHeap();
135         else WARN( "Shared Heap requested, returning system heap.\n" );
136         ret = systemHeap;
137     }
138     else
139     {
140         ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
141         if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
142     }
143     return ret;
144 }
145
146
147 /***********************************************************************
148  *           HeapDestroy   (KERNEL32.@)
149  * RETURNS
150  *      TRUE: Success
151  *      FALSE: Failure
152  */
153 BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
154 {
155     if (heap == systemHeap)
156     {
157         WARN( "attempt to destroy system heap, returning TRUE!\n" );
158         return TRUE;
159     }
160     if (!RtlDestroyHeap( heap )) return TRUE;
161     SetLastError( ERROR_INVALID_HANDLE );
162     return FALSE;
163 }
164
165
166 /***********************************************************************
167  *           HeapCompact   (KERNEL32.@)
168  */
169 SIZE_T WINAPI HeapCompact( HANDLE heap, DWORD flags )
170 {
171     return RtlCompactHeap( heap, flags );
172 }
173
174
175 /***********************************************************************
176  *           HeapValidate   (KERNEL32.@)
177  * Validates a specified heap.
178  *
179  * NOTES
180  *      Flags is ignored.
181  *
182  * RETURNS
183  *      TRUE: Success
184  *      FALSE: Failure
185  */
186 BOOL WINAPI HeapValidate(
187               HANDLE heap, /* [in] Handle to the heap */
188               DWORD flags,   /* [in] Bit flags that control access during operation */
189               LPCVOID block  /* [in] Optional pointer to memory block to validate */
190 ) {
191     return RtlValidateHeap( heap, flags, block );
192 }
193
194
195 /***********************************************************************
196  *           HeapWalk   (KERNEL32.@)
197  * Enumerates the memory blocks in a specified heap.
198  *
199  * TODO
200  *   - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
201  *     PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
202  *
203  * RETURNS
204  *      TRUE: Success
205  *      FALSE: Failure
206  */
207 BOOL WINAPI HeapWalk(
208               HANDLE heap,               /* [in]  Handle to heap to enumerate */
209               LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
210 ) {
211     NTSTATUS ret = RtlWalkHeap( heap, entry );
212     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
213     return !ret;
214 }
215
216
217 /***********************************************************************
218  *           HeapLock   (KERNEL32.@)
219  * Attempts to acquire the critical section object for a specified heap.
220  *
221  * RETURNS
222  *      TRUE: Success
223  *      FALSE: Failure
224  */
225 BOOL WINAPI HeapLock(
226               HANDLE heap /* [in] Handle of heap to lock for exclusive access */
227 ) {
228     return RtlLockHeap( heap );
229 }
230
231
232 /***********************************************************************
233  *           HeapUnlock   (KERNEL32.@)
234  * Releases ownership of the critical section object.
235  *
236  * RETURNS
237  *      TRUE: Success
238  *      FALSE: Failure
239  */
240 BOOL WINAPI HeapUnlock(
241               HANDLE heap /* [in] Handle to the heap to unlock */
242 ) {
243     return RtlUnlockHeap( heap );
244 }
245
246
247 /***********************************************************************
248  *           GetProcessHeap    (KERNEL32.@)
249  */
250 HANDLE WINAPI GetProcessHeap(void)
251 {
252     return NtCurrentTeb()->Peb->ProcessHeap;
253 }
254
255
256 /***********************************************************************
257  *           GetProcessHeaps    (KERNEL32.@)
258  */
259 DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
260 {
261     return RtlGetProcessHeaps( count, heaps );
262 }
263
264
265 /* These are needed so that we can call the functions from inside kernel itself */
266
267 LPVOID WINAPI HeapAlloc( HANDLE heap, DWORD flags, SIZE_T size )
268 {
269     return RtlAllocateHeap( heap, flags, size );
270 }
271
272 BOOL WINAPI HeapFree( HANDLE heap, DWORD flags, LPVOID ptr )
273 {
274     return RtlFreeHeap( heap, flags, ptr );
275 }
276
277 LPVOID WINAPI HeapReAlloc( HANDLE heap, DWORD flags, LPVOID ptr, SIZE_T size )
278 {
279     return RtlReAllocateHeap( heap, flags, ptr, size );
280 }
281
282 SIZE_T WINAPI HeapSize( HANDLE heap, DWORD flags, LPVOID ptr )
283 {
284     return RtlSizeHeap( heap, flags, ptr );
285 }
286
287 /*
288  * Win32 Global heap functions (GlobalXXX).
289  * These functions included in Win32 for compatibility with 16 bit Windows
290  * Especially the moveable blocks and handles are oldish.
291  * But the ability to directly allocate memory with GPTR and LPTR is widely
292  * used.
293  *
294  * The handle stuff looks horrible, but it's implemented almost like Win95
295  * does it.
296  *
297  */
298
299 #define MAGIC_GLOBAL_USED 0x5342
300 #define GLOBAL_LOCK_MAX   0xFF
301 #define HANDLE_TO_INTERN(h)  ((PGLOBAL32_INTERN)(((char *)(h))-2))
302 #define INTERN_TO_HANDLE(i)  ((HGLOBAL) &((i)->Pointer))
303 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL *)(p))-2))
304 #define ISHANDLE(h)          (((ULONG_PTR)(h)&2)!=0)
305 #define ISPOINTER(h)         (((ULONG_PTR)(h)&2)==0)
306 /* align the storage needed for the HGLOBAL on an 8byte boundary thus
307  * GlobalAlloc/GlobalReAlloc'ing with GMEM_MOVEABLE of memory with
308  * size = 8*k, where k=1,2,3,... alloc's exactly the given size.
309  * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
310  * the output jpeg's > 1 MB if not */
311 #define HGLOBAL_STORAGE      8  /* sizeof(HGLOBAL)*2 */
312
313 #include "pshpack1.h"
314
315 typedef struct __GLOBAL32_INTERN
316 {
317    WORD         Magic;
318    LPVOID       Pointer;
319    BYTE         Flags;
320    BYTE         LockCount;
321 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
322
323 #include "poppack.h"
324
325 /***********************************************************************
326  *           GlobalAlloc   (KERNEL32.@)
327  * RETURNS
328  *      Handle: Success
329  *      NULL: Failure
330  */
331 HGLOBAL WINAPI GlobalAlloc(
332                  UINT flags, /* [in] Object allocation attributes */
333                  SIZE_T size /* [in] Number of bytes to allocate */
334 ) {
335    PGLOBAL32_INTERN     pintern;
336    DWORD                hpflags;
337    LPVOID               palloc;
338
339    if(flags&GMEM_ZEROINIT)
340       hpflags=HEAP_ZERO_MEMORY;
341    else
342       hpflags=0;
343
344    TRACE("() flags=%04x\n",  flags );
345
346    if((flags & GMEM_MOVEABLE)==0) /* POINTER */
347    {
348       palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
349       return (HGLOBAL) palloc;
350    }
351    else  /* HANDLE */
352    {
353       RtlLockHeap(GetProcessHeap());
354
355       pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
356       if (pintern)
357       {
358           pintern->Magic = MAGIC_GLOBAL_USED;
359           pintern->Flags = flags >> 8;
360           pintern->LockCount = 0;
361
362           if (size)
363           {
364               palloc = HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE);
365               if (!palloc)
366               {
367                   HeapFree(GetProcessHeap(), 0, pintern);
368                   pintern = NULL;
369               }
370               else
371               {
372                   *(HGLOBAL *)palloc = INTERN_TO_HANDLE(pintern);
373                   pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
374               }
375           }
376           else
377               pintern->Pointer = NULL;
378       }
379
380       RtlUnlockHeap(GetProcessHeap());
381       return pintern ? INTERN_TO_HANDLE(pintern) : 0;
382    }
383 }
384
385
386 /***********************************************************************
387  *           GlobalLock   (KERNEL32.@)
388  * RETURNS
389  *      Pointer to first byte of block
390  *      NULL: Failure
391  */
392 LPVOID WINAPI GlobalLock(
393               HGLOBAL hmem /* [in] Handle of global memory object */
394 )
395 {
396     PGLOBAL32_INTERN pintern;
397     LPVOID           palloc;
398
399     if (ISPOINTER(hmem))
400         return IsBadReadPtr(hmem, 1) ? NULL : hmem;
401
402     RtlLockHeap(GetProcessHeap());
403     __TRY
404     {
405         pintern = HANDLE_TO_INTERN(hmem);
406         if (pintern->Magic == MAGIC_GLOBAL_USED)
407         {
408             if (pintern->LockCount < GLOBAL_LOCK_MAX)
409                 pintern->LockCount++;
410             palloc = pintern->Pointer;
411         }
412         else
413         {
414             WARN("invalid handle %p\n", hmem);
415             palloc = NULL;
416             SetLastError(ERROR_INVALID_HANDLE);
417         }
418     }
419     __EXCEPT(page_fault)
420     {
421         WARN("page fault on %p\n", hmem);
422         palloc = NULL;
423         SetLastError(ERROR_INVALID_HANDLE);
424     }
425     __ENDTRY
426     RtlUnlockHeap(GetProcessHeap());
427     return palloc;
428 }
429
430
431 /***********************************************************************
432  *           GlobalUnlock   (KERNEL32.@)
433  * RETURNS
434  *      TRUE: Object is still locked
435  *      FALSE: Object is unlocked
436  */
437 BOOL WINAPI GlobalUnlock(
438               HGLOBAL hmem /* [in] Handle of global memory object */
439 ) {
440     PGLOBAL32_INTERN pintern;
441     BOOL locked;
442
443     if (ISPOINTER(hmem)) return FALSE;
444
445     RtlLockHeap(GetProcessHeap());
446     __TRY
447     {
448         pintern=HANDLE_TO_INTERN(hmem);
449         if(pintern->Magic==MAGIC_GLOBAL_USED)
450         {
451             if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
452                 pintern->LockCount--;
453
454             locked = (pintern->LockCount != 0);
455             if (!locked) SetLastError(NO_ERROR);
456         }
457         else
458         {
459             WARN("invalid handle\n");
460             SetLastError(ERROR_INVALID_HANDLE);
461             locked=FALSE;
462         }
463     }
464     __EXCEPT(page_fault)
465     {
466         ERR("page fault occurred ! Caused by bug ?\n");
467         SetLastError( ERROR_INVALID_PARAMETER );
468         locked=FALSE;
469     }
470     __ENDTRY
471     RtlUnlockHeap(GetProcessHeap());
472     return locked;
473 }
474
475
476 /***********************************************************************
477  *           GlobalHandle   (KERNEL32.@)
478  * Returns the handle associated with the specified pointer.
479  *
480  * RETURNS
481  *      Handle: Success
482  *      NULL: Failure
483  */
484 HGLOBAL WINAPI GlobalHandle(
485                  LPCVOID pmem /* [in] Pointer to global memory block */
486 ) {
487     HGLOBAL handle;
488     PGLOBAL32_INTERN  maybe_intern;
489     LPCVOID test;
490
491     if (!pmem)
492     {
493         SetLastError( ERROR_INVALID_PARAMETER );
494         return 0;
495     }
496
497     RtlLockHeap(GetProcessHeap());
498     __TRY
499     {
500         handle = 0;
501
502         /* note that if pmem is a pointer to a a block allocated by        */
503         /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate  */
504         /* will fail.                                                      */
505         if (ISPOINTER(pmem)) {
506             if (HeapValidate( GetProcessHeap(), 0, pmem )) {
507                 handle = (HGLOBAL)pmem;  /* valid fixed block */
508                 break;
509             }
510             handle = POINTER_TO_HANDLE(pmem);
511         } else
512             handle = (HGLOBAL)pmem;
513
514         /* Now test handle either passed in or retrieved from pointer */
515         maybe_intern = HANDLE_TO_INTERN( handle );
516         if (maybe_intern->Magic == MAGIC_GLOBAL_USED) {
517             test = maybe_intern->Pointer;
518             if (HeapValidate( GetProcessHeap(), 0, (const char *)test - HGLOBAL_STORAGE ) && /* obj(-handle) valid arena? */
519                 HeapValidate( GetProcessHeap(), 0, maybe_intern ))  /* intern valid arena? */
520                 break;  /* valid moveable block */
521         }
522         handle = 0;
523         SetLastError( ERROR_INVALID_HANDLE );
524     }
525     __EXCEPT(page_fault)
526     {
527         SetLastError( ERROR_INVALID_HANDLE );
528         handle = 0;
529     }
530     __ENDTRY
531     RtlUnlockHeap(GetProcessHeap());
532
533     return handle;
534 }
535
536
537 /***********************************************************************
538  *           GlobalReAlloc   (KERNEL32.@)
539  * RETURNS
540  *      Handle: Success
541  *      NULL: Failure
542  */
543 HGLOBAL WINAPI GlobalReAlloc(
544                  HGLOBAL hmem, /* [in] Handle of global memory object */
545                  SIZE_T size,  /* [in] New size of block */
546                  UINT flags    /* [in] How to reallocate object */
547 ) {
548    LPVOID               palloc;
549    HGLOBAL            hnew;
550    PGLOBAL32_INTERN     pintern;
551    DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
552
553    hnew = 0;
554    RtlLockHeap(GetProcessHeap());
555    if(flags & GMEM_MODIFY) /* modify flags */
556    {
557       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
558       {
559          /* make a fixed block moveable
560           * actually only NT is able to do this. But it's soo simple
561           */
562          if (hmem == 0)
563          {
564              WARN("GlobalReAlloc with null handle!\n");
565              SetLastError( ERROR_NOACCESS );
566              hnew = 0;
567          }
568          else
569          {
570              size = HeapSize(GetProcessHeap(), 0, (LPVOID)hmem);
571              hnew = GlobalAlloc(flags, size);
572              palloc = GlobalLock(hnew);
573              memcpy(palloc, (LPVOID)hmem, size);
574              GlobalUnlock(hnew);
575              GlobalFree(hmem);
576          }
577       }
578       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
579       {
580          /* change the flags to make our block "discardable" */
581          pintern=HANDLE_TO_INTERN(hmem);
582          pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
583          hnew=hmem;
584       }
585       else
586       {
587          SetLastError(ERROR_INVALID_PARAMETER);
588          hnew = 0;
589       }
590    }
591    else
592    {
593       if(ISPOINTER(hmem))
594       {
595          /* reallocate fixed memory */
596          hnew=HeapReAlloc(GetProcessHeap(), heap_flags, hmem, size);
597       }
598       else
599       {
600          /* reallocate a moveable block */
601          pintern=HANDLE_TO_INTERN(hmem);
602
603 #if 0
604 /* Apparently Windows doesn't care whether the handle is locked at this point */
605 /* See also the same comment in GlobalFree() */
606          if(pintern->LockCount>1) {
607             ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
608             SetLastError(ERROR_INVALID_HANDLE);
609          } else
610 #endif
611          if(size!=0)
612          {
613             hnew=hmem;
614             if(pintern->Pointer)
615             {
616                if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags,
617                                    (char *) pintern->Pointer-HGLOBAL_STORAGE,
618                                    size+HGLOBAL_STORAGE)) == NULL)
619                    hnew = 0; /* Block still valid */
620                else
621                    pintern->Pointer = (char *)palloc+HGLOBAL_STORAGE;
622             }
623             else
624             {
625                 if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE))
626                    == NULL)
627                     hnew = 0;
628                 else
629                 {
630                     *(HGLOBAL *)palloc = hmem;
631                     pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
632                 }
633             }
634          }
635          else
636          {
637             if(pintern->Pointer)
638             {
639                HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE);
640                pintern->Pointer=NULL;
641             }
642          }
643       }
644    }
645    RtlUnlockHeap(GetProcessHeap());
646    return hnew;
647 }
648
649
650 /***********************************************************************
651  *           GlobalFree   (KERNEL32.@)
652  * RETURNS
653  *      NULL: Success
654  *      Handle: Failure
655  */
656 HGLOBAL WINAPI GlobalFree(
657                  HGLOBAL hmem /* [in] Handle of global memory object */
658 ) {
659     PGLOBAL32_INTERN pintern;
660     HGLOBAL hreturned;
661
662     RtlLockHeap(GetProcessHeap());
663     __TRY
664     {
665         hreturned = 0;
666         if(ISPOINTER(hmem)) /* POINTER */
667         {
668             if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
669         }
670         else  /* HANDLE */
671         {
672             pintern=HANDLE_TO_INTERN(hmem);
673
674             if(pintern->Magic==MAGIC_GLOBAL_USED)
675             {
676
677                 /* WIN98 does not make this test. That is you can free a */
678                 /* block you have not unlocked. Go figure!!              */
679                 /* if(pintern->LockCount!=0)  */
680                 /*    SetLastError(ERROR_INVALID_HANDLE);  */
681
682                 if(pintern->Pointer)
683                     if(!HeapFree(GetProcessHeap(), 0, (char *)(pintern->Pointer)-HGLOBAL_STORAGE))
684                         hreturned=hmem;
685                 if(!HeapFree(GetProcessHeap(), 0, pintern))
686                     hreturned=hmem;
687             }
688         }
689     }
690     __EXCEPT(page_fault)
691     {
692         ERR("page fault occurred ! Caused by bug ?\n");
693         SetLastError( ERROR_INVALID_PARAMETER );
694         hreturned = hmem;
695     }
696     __ENDTRY
697     RtlUnlockHeap(GetProcessHeap());
698     return hreturned;
699 }
700
701
702 /***********************************************************************
703  *           GlobalSize   (KERNEL32.@)
704  * RETURNS
705  *      Size in bytes of the global memory object
706  *      0: Failure
707  */
708 SIZE_T WINAPI GlobalSize(
709              HGLOBAL hmem /* [in] Handle of global memory object */
710 ) {
711    DWORD                retval;
712    PGLOBAL32_INTERN     pintern;
713
714    if (!hmem) return 0;
715
716    if(ISPOINTER(hmem))
717    {
718       retval=HeapSize(GetProcessHeap(), 0,  (LPVOID) hmem);
719    }
720    else
721    {
722       RtlLockHeap(GetProcessHeap());
723       pintern=HANDLE_TO_INTERN(hmem);
724
725       if(pintern->Magic==MAGIC_GLOBAL_USED)
726       {
727          if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */
728              retval = 0;
729          else
730          {
731              retval = HeapSize(GetProcessHeap(), 0,
732                          (char *)(pintern->Pointer) - HGLOBAL_STORAGE );
733              if (retval != (DWORD)-1) retval -= HGLOBAL_STORAGE;
734          }
735       }
736       else
737       {
738          WARN("invalid handle\n");
739          retval=0;
740       }
741       RtlUnlockHeap(GetProcessHeap());
742    }
743    /* HeapSize returns 0xffffffff on failure */
744    if (retval == 0xffffffff) retval = 0;
745    return retval;
746 }
747
748
749 /***********************************************************************
750  *           GlobalWire   (KERNEL32.@)
751  */
752 LPVOID WINAPI GlobalWire(HGLOBAL hmem)
753 {
754    return GlobalLock( hmem );
755 }
756
757
758 /***********************************************************************
759  *           GlobalUnWire   (KERNEL32.@)
760  */
761 BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
762 {
763    return GlobalUnlock( hmem);
764 }
765
766
767 /***********************************************************************
768  *           GlobalFix   (KERNEL32.@)
769  */
770 VOID WINAPI GlobalFix(HGLOBAL hmem)
771 {
772     GlobalLock( hmem );
773 }
774
775
776 /***********************************************************************
777  *           GlobalUnfix   (KERNEL32.@)
778  */
779 VOID WINAPI GlobalUnfix(HGLOBAL hmem)
780 {
781    GlobalUnlock( hmem);
782 }
783
784
785 /***********************************************************************
786  *           GlobalFlags   (KERNEL32.@)
787  * Returns information about the specified global memory object
788  *
789  * NOTES
790  *      Should this return GMEM_INVALID_HANDLE on invalid handle?
791  *
792  * RETURNS
793  *      Value specifying allocation flags and lock count
794  *      GMEM_INVALID_HANDLE: Failure
795  */
796 UINT WINAPI GlobalFlags(
797               HGLOBAL hmem /* [in] Handle to global memory object */
798 ) {
799    DWORD                retval;
800    PGLOBAL32_INTERN     pintern;
801
802    if(ISPOINTER(hmem))
803    {
804       retval=0;
805    }
806    else
807    {
808       RtlLockHeap(GetProcessHeap());
809       pintern=HANDLE_TO_INTERN(hmem);
810       if(pintern->Magic==MAGIC_GLOBAL_USED)
811       {
812          retval=pintern->LockCount + (pintern->Flags<<8);
813          if(pintern->Pointer==0)
814             retval|= GMEM_DISCARDED;
815       }
816       else
817       {
818          WARN("Invalid handle: %p\n", hmem);
819          retval=0;
820       }
821       RtlUnlockHeap(GetProcessHeap());
822    }
823    return retval;
824 }
825
826
827 /***********************************************************************
828  *           GlobalCompact   (KERNEL32.@)
829  */
830 SIZE_T WINAPI GlobalCompact( DWORD minfree )
831 {
832     return 0;  /* GlobalCompact does nothing in Win32 */
833 }
834
835
836 /***********************************************************************
837  *           LocalAlloc   (KERNEL32.@)
838  * RETURNS
839  *      Handle: Success
840  *      NULL: Failure
841  */
842 HLOCAL WINAPI LocalAlloc(
843                 UINT flags, /* [in] Allocation attributes */
844                 SIZE_T size /* [in] Number of bytes to allocate */
845 ) {
846     return (HLOCAL)GlobalAlloc( flags, size );
847 }
848
849
850 /***********************************************************************
851  *           LocalCompact   (KERNEL32.@)
852  */
853 SIZE_T WINAPI LocalCompact( UINT minfree )
854 {
855     return 0;  /* LocalCompact does nothing in Win32 */
856 }
857
858
859 /***********************************************************************
860  *           LocalFlags   (KERNEL32.@)
861  * RETURNS
862  *      Value specifying allocation flags and lock count.
863  *      LMEM_INVALID_HANDLE: Failure
864  */
865 UINT WINAPI LocalFlags(
866               HLOCAL handle /* [in] Handle of memory object */
867 ) {
868     return GlobalFlags( (HGLOBAL)handle );
869 }
870
871
872 /***********************************************************************
873  *           LocalFree   (KERNEL32.@)
874  * RETURNS
875  *      NULL: Success
876  *      Handle: Failure
877  */
878 HLOCAL WINAPI LocalFree(
879                 HLOCAL handle /* [in] Handle of memory object */
880 ) {
881     return (HLOCAL)GlobalFree( (HGLOBAL)handle );
882 }
883
884
885 /***********************************************************************
886  *           LocalHandle   (KERNEL32.@)
887  * RETURNS
888  *      Handle: Success
889  *      NULL: Failure
890  */
891 HLOCAL WINAPI LocalHandle(
892                 LPCVOID ptr /* [in] Address of local memory object */
893 ) {
894     return (HLOCAL)GlobalHandle( ptr );
895 }
896
897
898 /***********************************************************************
899  *           LocalLock   (KERNEL32.@)
900  * Locks a local memory object and returns pointer to the first byte
901  * of the memory block.
902  *
903  * RETURNS
904  *      Pointer: Success
905  *      NULL: Failure
906  */
907 LPVOID WINAPI LocalLock(
908               HLOCAL handle /* [in] Address of local memory object */
909 ) {
910     return GlobalLock( (HGLOBAL)handle );
911 }
912
913
914 /***********************************************************************
915  *           LocalReAlloc   (KERNEL32.@)
916  * RETURNS
917  *      Handle: Success
918  *      NULL: Failure
919  */
920 HLOCAL WINAPI LocalReAlloc(
921                 HLOCAL handle, /* [in] Handle of memory object */
922                 SIZE_T size,   /* [in] New size of block */
923                 UINT flags     /* [in] How to reallocate object */
924 ) {
925     return (HLOCAL)GlobalReAlloc( (HGLOBAL)handle, size, flags );
926 }
927
928
929 /***********************************************************************
930  *           LocalShrink   (KERNEL32.@)
931  */
932 SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize )
933 {
934     return 0;  /* LocalShrink does nothing in Win32 */
935 }
936
937
938 /***********************************************************************
939  *           LocalSize   (KERNEL32.@)
940  * RETURNS
941  *      Size: Success
942  *      0: Failure
943  */
944 SIZE_T WINAPI LocalSize(
945               HLOCAL handle /* [in] Handle of memory object */
946 ) {
947     return GlobalSize( (HGLOBAL)handle );
948 }
949
950
951 /***********************************************************************
952  *           LocalUnlock   (KERNEL32.@)
953  * RETURNS
954  *      TRUE: Object is still locked
955  *      FALSE: Object is unlocked
956  */
957 BOOL WINAPI LocalUnlock(
958               HLOCAL handle /* [in] Handle of memory object */
959 ) {
960     return GlobalUnlock( (HGLOBAL)handle );
961 }
962
963
964 /**********************************************************************
965  *              AllocMappedBuffer       (KERNEL32.38)
966  *
967  * This is an undocumented KERNEL32 function that
968  * SMapLS's a GlobalAlloc'ed buffer.
969  *
970  * Input:   EDI register: size of buffer to allocate
971  * Output:  EDI register: pointer to buffer
972  *
973  * Note: The buffer is preceded by 8 bytes:
974  *        ...
975  *       edi+0   buffer
976  *       edi-4   SEGPTR to buffer
977  *       edi-8   some magic Win95 needs for SUnMapLS
978  *               (we use it for the memory handle)
979  *
980  *       The SEGPTR is used by the caller!
981  */
982 void WINAPI __regs_AllocMappedBuffer( CONTEXT86 *context )
983 {
984     HGLOBAL handle = GlobalAlloc(0, context->Edi + 8);
985     DWORD *buffer = (DWORD *)GlobalLock(handle);
986     DWORD ptr = 0;
987
988     if (buffer)
989         if (!(ptr = MapLS(buffer + 2)))
990         {
991             GlobalUnlock(handle);
992             GlobalFree(handle);
993         }
994
995     if (!ptr)
996         context->Eax = context->Edi = 0;
997     else
998     {
999         buffer[0] = (DWORD)handle;
1000         buffer[1] = ptr;
1001
1002         context->Eax = (DWORD) ptr;
1003         context->Edi = (DWORD)(buffer + 2);
1004     }
1005 }
1006 #ifdef DEFINE_REGS_ENTRYPOINT
1007 DEFINE_REGS_ENTRYPOINT( AllocMappedBuffer, 0, 0 );
1008 #endif
1009
1010 /**********************************************************************
1011  *              FreeMappedBuffer        (KERNEL32.39)
1012  *
1013  * Free a buffer allocated by AllocMappedBuffer
1014  *
1015  * Input: EDI register: pointer to buffer
1016  */
1017 void WINAPI __regs_FreeMappedBuffer( CONTEXT86 *context )
1018 {
1019     if (context->Edi)
1020     {
1021         DWORD *buffer = (DWORD *)context->Edi - 2;
1022
1023         UnMapLS(buffer[1]);
1024
1025         GlobalUnlock((HGLOBAL)buffer[0]);
1026         GlobalFree((HGLOBAL)buffer[0]);
1027     }
1028 }
1029 #ifdef DEFINE_REGS_ENTRYPOINT
1030 DEFINE_REGS_ENTRYPOINT( FreeMappedBuffer, 0, 0 );
1031 #endif
1032
1033 /***********************************************************************
1034  *           GlobalMemoryStatusEx   (KERNEL32.@)
1035  * A version of GlobalMemoryStatus that can deal with memory over 4GB
1036  *
1037  * RETURNS
1038  *      TRUE
1039  */
1040 BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpmemex )
1041 {
1042     static MEMORYSTATUSEX       cached_memstatus;
1043     static int cache_lastchecked = 0;
1044     SYSTEM_INFO si;
1045 #ifdef linux
1046     FILE *f;
1047 #endif
1048 #if defined(__FreeBSD__) || defined(__NetBSD__)
1049     int *tmp;
1050     int size_sys;
1051     int mib[2] = { CTL_HW };
1052 #endif
1053     if (time(NULL)==cache_lastchecked) {
1054         memcpy(lpmemex,&cached_memstatus,sizeof(*lpmemex));
1055         return TRUE;
1056     }
1057     cache_lastchecked = time(NULL);
1058
1059     lpmemex->dwLength         = sizeof(*lpmemex);
1060     lpmemex->dwMemoryLoad     = 0;
1061     lpmemex->ullTotalPhys     = 16*1024*1024;
1062     lpmemex->ullAvailPhys     = 16*1024*1024;
1063     lpmemex->ullTotalPageFile = 16*1024*1024;
1064     lpmemex->ullAvailPageFile = 16*1024*1024;
1065
1066 #ifdef linux
1067     f = fopen( "/proc/meminfo", "r" );
1068     if (f)
1069     {
1070         char buffer[256];
1071         int total, used, free, shared, buffers, cached;
1072
1073         lpmemex->ullTotalPhys = lpmemex->ullAvailPhys = 0;
1074         lpmemex->ullTotalPageFile = lpmemex->ullAvailPageFile = 0;
1075         while (fgets( buffer, sizeof(buffer), f ))
1076         {
1077             /* old style /proc/meminfo ... */
1078             if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
1079             {
1080                 lpmemex->ullTotalPhys += total;
1081                 lpmemex->ullAvailPhys += free + buffers + cached;
1082             }
1083             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1084             {
1085                 lpmemex->ullTotalPageFile += total;
1086                 lpmemex->ullAvailPageFile += free;
1087             }
1088
1089             /* new style /proc/meminfo ... */
1090             if (sscanf(buffer, "MemTotal: %d", &total))
1091                 lpmemex->ullTotalPhys = total*1024;
1092             if (sscanf(buffer, "MemFree: %d", &free))
1093                 lpmemex->ullAvailPhys = free*1024;
1094             if (sscanf(buffer, "SwapTotal: %d", &total))
1095                 lpmemex->ullTotalPageFile = total*1024;
1096             if (sscanf(buffer, "SwapFree: %d", &free))
1097                 lpmemex->ullAvailPageFile = free*1024;
1098             if (sscanf(buffer, "Buffers: %d", &buffers))
1099                 lpmemex->ullAvailPhys += buffers*1024;
1100             if (sscanf(buffer, "Cached: %d", &cached))
1101                 lpmemex->ullAvailPhys += cached*1024;
1102         }
1103         fclose( f );
1104
1105         if (lpmemex->ullTotalPhys)
1106         {
1107             DWORDLONG TotalPhysical = lpmemex->ullTotalPhys+lpmemex->ullTotalPageFile;
1108             DWORDLONG AvailPhysical = lpmemex->ullAvailPhys+lpmemex->ullAvailPageFile;
1109             lpmemex->dwMemoryLoad = (TotalPhysical-AvailPhysical)
1110                                       / (TotalPhysical / 100);
1111         }
1112     }
1113 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1114     mib[1] = HW_PHYSMEM;
1115     sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1116     tmp = malloc(size_sys * sizeof(int));
1117     sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1118     if (tmp && *tmp)
1119     {
1120         lpmemex->ullTotalPhys = *tmp;
1121         free(tmp);
1122         mib[1] = HW_USERMEM;
1123         sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1124         tmp = malloc(size_sys * sizeof(int));
1125         sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1126         if (tmp && *tmp)
1127         {
1128             lpmemex->ullAvailPhys = *tmp;
1129             lpmemex->ullTotalPageFile = *tmp;
1130             lpmemex->ullAvailPageFile = *tmp;
1131             lpmemex->dwMemoryLoad = lpmemex->ullTotalPhys - lpmemex->ullAvailPhys;
1132         } else
1133         {
1134             lpmemex->ullAvailPhys = lpmemex->ullTotalPhys;
1135             lpmemex->ullTotalPageFile = lpmemex->ullTotalPhys;
1136             lpmemex->ullAvailPageFile = lpmemex->ullTotalPhys;
1137             lpmemex->dwMemoryLoad = 0;
1138         }
1139         free(tmp);
1140
1141     }
1142 #endif
1143
1144     /* FIXME: should do something for other systems */
1145     GetSystemInfo(&si);
1146     lpmemex->ullTotalVirtual  = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
1147     /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
1148     lpmemex->ullAvailVirtual  = lpmemex->ullTotalVirtual-64*1024;
1149     memcpy(&cached_memstatus,lpmemex,sizeof(*lpmemex));
1150
1151     /* it appears some memory display programs want to divide by these values */
1152     if(lpmemex->ullTotalPageFile==0)
1153         lpmemex->ullTotalPageFile++;
1154
1155     if(lpmemex->ullAvailPageFile==0)
1156         lpmemex->ullAvailPageFile++;
1157
1158     /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
1159        memory in the extended portion of the virtual address space of the calling
1160        process, in bytes.
1161        However, I don't know what this means, so set it to zero :(
1162     */
1163     lpmemex->ullAvailExtendedVirtual = 0;
1164
1165     TRACE("<-- LPMEMORYSTATUSEX: dwLength %ld, dwMemoryLoad %ld, ullTotalPhys %s, ullAvailPhys %s,"
1166           " ullTotalPageFile %s, ullAvailPageFile %s, ullTotalVirtual %s, ullAvailVirtual %s\n",
1167           lpmemex->dwLength, lpmemex->dwMemoryLoad, wine_dbgstr_longlong(lpmemex->ullTotalPhys),
1168           wine_dbgstr_longlong(lpmemex->ullAvailPhys), wine_dbgstr_longlong(lpmemex->ullTotalPageFile),
1169           wine_dbgstr_longlong(lpmemex->ullAvailPageFile), wine_dbgstr_longlong(lpmemex->ullTotalVirtual),
1170           wine_dbgstr_longlong(lpmemex->ullAvailVirtual) );
1171
1172     return TRUE;
1173 }
1174
1175 /***********************************************************************
1176  *           GlobalMemoryStatus   (KERNEL32.@)
1177  * Provides information about the status of the memory, so apps can tell
1178  * roughly how much they are able to allocate
1179  *
1180  * RETURNS
1181  *      None
1182  */
1183 VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer )
1184 {
1185     MEMORYSTATUSEX memstatus;
1186     OSVERSIONINFOW osver;
1187
1188     /* Because GlobalMemoryStatus is identical to GlobalMemoryStatusEX save
1189        for one extra field in the struct, and the lack of a bug, we simply
1190        call GlobalMemoryStatusEx and copy the values across. */
1191     GlobalMemoryStatusEx(&memstatus);
1192
1193     lpBuffer->dwLength = sizeof(*lpBuffer);
1194     lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
1195
1196     /* Windows 2000 and later report -1 when values are greater than 4 Gb.
1197      * NT reports values modulo 4 Gb.
1198      * Values between 2 Gb and 4 Gb are rounded down to 2 Gb.
1199      */
1200
1201     osver.dwOSVersionInfoSize = sizeof(osver);
1202     GetVersionExW(&osver);
1203
1204     if ( osver.dwMajorVersion >= 5 )
1205     {
1206         lpBuffer->dwTotalPhys = (memstatus.ullTotalPhys > MAXDWORD) ? MAXDWORD :
1207                                 (memstatus.ullTotalPhys > MAXLONG) ? MAXLONG : memstatus.ullTotalPhys;
1208         lpBuffer->dwAvailPhys = (memstatus.ullAvailPhys > MAXDWORD) ? MAXDWORD :
1209                                 (memstatus.ullAvailPhys > MAXLONG) ? MAXLONG : memstatus.ullAvailPhys; 
1210         lpBuffer->dwTotalPageFile = (memstatus.ullTotalPageFile > MAXDWORD) ? MAXDWORD :
1211                                     (memstatus.ullTotalPageFile > MAXLONG) ? MAXLONG : memstatus.ullTotalPageFile;
1212         lpBuffer->dwAvailPageFile = (memstatus.ullAvailPageFile > MAXDWORD) ? MAXDWORD :
1213                                     (memstatus.ullAvailPageFile > MAXLONG) ? MAXLONG : memstatus.ullAvailPageFile;
1214         lpBuffer->dwTotalVirtual = (memstatus.ullTotalVirtual > MAXDWORD) ? MAXDWORD :
1215                                    (memstatus.ullTotalVirtual > MAXLONG)  ? MAXLONG : memstatus.ullTotalVirtual;
1216         lpBuffer->dwAvailVirtual = (memstatus.ullAvailVirtual > MAXDWORD) ? MAXDWORD :
1217                                    (memstatus.ullAvailVirtual > MAXLONG) ? MAXLONG : memstatus.ullAvailVirtual;
1218     }
1219     else        /* duplicate NT bug */
1220     {
1221         lpBuffer->dwTotalPhys = (memstatus.ullTotalPhys > MAXDWORD) ? memstatus.ullTotalPhys :
1222                                 (memstatus.ullTotalPhys > MAXLONG) ? MAXLONG : memstatus.ullTotalPhys;
1223         lpBuffer->dwAvailPhys = (memstatus.ullAvailPhys > MAXDWORD) ? memstatus.ullAvailPhys :
1224                                 (memstatus.ullAvailPhys > MAXLONG) ? MAXLONG : memstatus.ullAvailPhys;
1225         lpBuffer->dwTotalPageFile = (memstatus.ullTotalPageFile > MAXDWORD) ? memstatus.ullTotalPageFile : 
1226                                     (memstatus.ullTotalPageFile > MAXLONG) ? MAXLONG : memstatus.ullTotalPageFile;
1227         lpBuffer->dwAvailPageFile = (memstatus.ullAvailPageFile > MAXDWORD) ? memstatus.ullAvailPageFile : 
1228                                     (memstatus.ullAvailPageFile > MAXLONG) ? MAXLONG : memstatus.ullAvailPageFile;
1229         lpBuffer->dwTotalVirtual = (memstatus.ullTotalVirtual > MAXDWORD) ? memstatus.ullTotalVirtual : 
1230                                    (memstatus.ullTotalVirtual > MAXLONG)  ? MAXLONG : memstatus.ullTotalVirtual;
1231         lpBuffer->dwAvailVirtual = (memstatus.ullAvailVirtual > MAXDWORD) ? memstatus.ullAvailVirtual :
1232                                    (memstatus.ullAvailVirtual > MAXLONG) ? MAXLONG : memstatus.ullAvailVirtual;
1233     }
1234
1235     /* work around for broken photoshop 4 installer */
1236     if ( lpBuffer->dwAvailPhys +  lpBuffer->dwAvailPageFile >= 2U*1024*1024*1024)
1237          lpBuffer->dwAvailPageFile = 2U*1024*1024*1024 -  lpBuffer->dwAvailPhys - 1;
1238 }