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