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