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