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