Added support for CP_UNIXCP.
[wine] / memory / global.c
1 /*
2  * Global heap functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 /* 0xffff sometimes seems to mean: CURRENT_DS */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <string.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
40 #include "wine/winbase16.h"
41 #include "wine/exception.h"
42 #include "global.h"
43 #include "toolhelp.h"
44 #include "selectors.h"
45 #include "miscemu.h"
46 #include "stackframe.h"
47 #include "wine/debug.h"
48 #include "winerror.h"
49 #include "excpt.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(global);
52
53   /* Global arena block */
54 typedef struct
55 {
56     DWORD     base;          /* Base address (0 if discarded) */
57     DWORD     size;          /* Size in bytes (0 indicates a free block) */
58     HGLOBAL16 handle;        /* Handle for this block */
59     HGLOBAL16 hOwner;        /* Owner of this block */
60     BYTE      lockCount;     /* Count of GlobalFix() calls */
61     BYTE      pageLockCount; /* Count of GlobalPageLock() calls */
62     BYTE      flags;         /* Allocation flags */
63     BYTE      selCount;      /* Number of selectors allocated for this block */
64 } GLOBALARENA;
65
66   /* Flags definitions */
67 #define GA_MOVEABLE     0x02  /* same as GMEM_MOVEABLE */
68 #define GA_DGROUP       0x04
69 #define GA_DISCARDABLE  0x08
70 #define GA_IPCSHARE     0x10  /* same as GMEM_DDESHARE */
71 #define GA_DOSMEM       0x20
72
73   /* Arena array */
74 static GLOBALARENA *pGlobalArena = NULL;
75 static int globalArenaSize = 0;
76
77 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
78
79 #define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
80 #define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
81
82 /* filter for page-fault exceptions */
83 /* It is possible for a bogus global pointer to cause a */
84 /* page zero reference, so I include EXCEPTION_PRIV_INSTRUCTION too. */
85
86 static WINE_EXCEPTION_FILTER(page_fault)
87 {
88     switch (GetExceptionCode()) {
89         case (EXCEPTION_ACCESS_VIOLATION):
90         case (EXCEPTION_PRIV_INSTRUCTION):
91            return EXCEPTION_EXECUTE_HANDLER;
92         default:
93            return EXCEPTION_CONTINUE_SEARCH;
94     }
95 }
96
97 /***********************************************************************
98  *           GLOBAL_GetArena
99  *
100  * Return the arena for a given selector, growing the arena array if needed.
101  */
102 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
103 {
104     if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
105     {
106         int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
107         GLOBALARENA *pNewArena = realloc( pGlobalArena,
108                                           newsize * sizeof(GLOBALARENA) );
109         if (!pNewArena) return 0;
110         pGlobalArena = pNewArena;
111         memset( pGlobalArena + globalArenaSize, 0,
112                 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
113         globalArenaSize = newsize;
114     }
115     return pGlobalArena + (sel >> __AHSHIFT);
116 }
117
118 void debug_handles(void)
119 {
120     int printed=0;
121     int i;
122     for (i = globalArenaSize-1 ; i>=0 ; i--) {
123         if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
124             printed=1;
125             DPRINTF("0x%08x, ",pGlobalArena[i].handle);
126         }
127     }
128     if (printed)
129         DPRINTF("\n");
130 }
131
132
133 /***********************************************************************
134  *           GLOBAL_CreateBlock
135  *
136  * Create a global heap block for a fixed range of linear memory.
137  */
138 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
139                               HGLOBAL16 hOwner, unsigned char selflags )
140 {
141     WORD sel, selcount;
142     GLOBALARENA *pArena;
143
144       /* Allocate the selector(s) */
145
146     sel = SELECTOR_AllocBlock( ptr, size, selflags );
147     if (!sel) return 0;
148     selcount = (size + 0xffff) / 0x10000;
149
150     if (!(pArena = GLOBAL_GetArena( sel, selcount )))
151     {
152         SELECTOR_FreeBlock( sel );
153         return 0;
154     }
155
156       /* Fill the arena block */
157
158     pArena->base = (DWORD)ptr;
159     pArena->size = GetSelectorLimit16(sel) + 1;
160     pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
161     pArena->hOwner = hOwner;
162     pArena->lockCount = 0;
163     pArena->pageLockCount = 0;
164     pArena->flags = flags & GA_MOVEABLE;
165     if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
166     if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
167     if (!(selflags & (WINE_LDT_FLAGS_CODE^WINE_LDT_FLAGS_DATA))) pArena->flags |= GA_DGROUP;
168     pArena->selCount = selcount;
169     if (selcount > 1)  /* clear the next arena blocks */
170         memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
171
172     return pArena->handle;
173 }
174
175
176 /***********************************************************************
177  *           GLOBAL_FreeBlock
178  *
179  * Free a block allocated by GLOBAL_CreateBlock, without touching
180  * the associated linear memory range.
181  */
182 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
183 {
184     WORD sel;
185     GLOBALARENA *pArena;
186
187     if (!handle) return TRUE;
188     sel = GlobalHandleToSel16( handle );
189     if (!VALID_HANDLE(sel))
190         return FALSE;
191     pArena = GET_ARENA_PTR(sel);
192     SELECTOR_FreeBlock( sel );
193     memset( pArena, 0, sizeof(GLOBALARENA) );
194     return TRUE;
195 }
196
197 /***********************************************************************
198  *           GLOBAL_MoveBlock
199  */
200 BOOL16 GLOBAL_MoveBlock( HGLOBAL16 handle, const void *ptr, DWORD size )
201 {
202     WORD sel;
203     GLOBALARENA *pArena;
204
205     if (!handle) return TRUE;
206     sel = GlobalHandleToSel16( handle );
207     if (!VALID_HANDLE(sel))
208         return FALSE;
209     pArena = GET_ARENA_PTR(sel);
210     if (pArena->selCount != 1)
211         return FALSE;
212
213     pArena->base = (DWORD)ptr;
214     pArena->size = size;
215     SELECTOR_ReallocBlock( sel, ptr, size );
216     return TRUE;
217 }
218
219 /***********************************************************************
220  *           GLOBAL_Alloc
221  *
222  * Implementation of GlobalAlloc16()
223  */
224 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner, unsigned char selflags )
225 {
226     void *ptr;
227     HGLOBAL16 handle;
228
229     TRACE("%ld flags=%04x\n", size, flags );
230
231     /* If size is 0, create a discarded block */
232
233     if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, selflags );
234
235     /* Fixup the size */
236
237     if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
238     size = (size + 0x1f) & ~0x1f;
239
240     /* Allocate the linear memory */
241     ptr = HeapAlloc( GetProcessHeap(), 0, size );
242       /* FIXME: free discardable blocks and try again? */
243     if (!ptr) return 0;
244
245       /* Allocate the selector(s) */
246
247     handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner, selflags );
248     if (!handle)
249     {
250         HeapFree( GetProcessHeap(), 0, ptr );
251         return 0;
252     }
253
254     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
255     return handle;
256 }
257
258 /***********************************************************************
259  *           GlobalAlloc     (KERNEL.15)
260  *           GlobalAlloc16   (KERNEL32.24)
261  * RETURNS
262  *      Handle: Success
263  *      NULL: Failure
264  */
265 HGLOBAL16 WINAPI GlobalAlloc16(
266                  UINT16 flags, /* [in] Object allocation attributes */
267                  DWORD size    /* [in] Number of bytes to allocate */
268 ) {
269     HANDLE16 owner = GetCurrentPDB16();
270
271     if (flags & GMEM_DDESHARE)
272         owner = GetExePtr(owner);  /* Make it a module handle */
273     return GLOBAL_Alloc( flags, size, owner, WINE_LDT_FLAGS_DATA );
274 }
275
276
277 /***********************************************************************
278  *           GlobalReAlloc     (KERNEL.16)
279  * RETURNS
280  *      Handle: Success
281  *      NULL: Failure
282  */
283 HGLOBAL16 WINAPI GlobalReAlloc16(
284                  HGLOBAL16 handle, /* [in] Handle of global memory object */
285                  DWORD size,       /* [in] New size of block */
286                  UINT16 flags      /* [in] How to reallocate object */
287 ) {
288     WORD selcount;
289     DWORD oldsize;
290     void *ptr, *newptr;
291     GLOBALARENA *pArena, *pNewArena;
292     WORD sel = GlobalHandleToSel16( handle );
293
294     TRACE("%04x %ld flags=%04x\n",
295                     handle, size, flags );
296     if (!handle) return 0;
297
298     if (!VALID_HANDLE(handle)) {
299         WARN("Invalid handle 0x%04x!\n", handle);
300         return 0;
301     }
302     pArena = GET_ARENA_PTR( handle );
303
304       /* Discard the block if requested */
305
306     if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
307     {
308         if (!(pArena->flags & GA_MOVEABLE) ||
309             !(pArena->flags & GA_DISCARDABLE) ||
310             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
311         if (pArena->flags & GA_DOSMEM)
312             DOSMEM_FreeBlock( (void *)pArena->base );
313         else
314             HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
315         pArena->base = 0;
316
317         /* Note: we rely on the fact that SELECTOR_ReallocBlock won't
318          * change the selector if we are shrinking the block.
319          * FIXME: shouldn't we keep selectors until the block is deleted?
320          */
321         SELECTOR_ReallocBlock( sel, 0, 1 );
322         return handle;
323     }
324
325       /* Fixup the size */
326
327     if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
328     if (size == 0) size = 0x20;
329     else size = (size + 0x1f) & ~0x1f;
330
331       /* Change the flags */
332
333     if (flags & GMEM_MODIFY)
334     {
335           /* Change the flags, leaving GA_DGROUP alone */
336         pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
337         if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
338         return handle;
339     }
340
341       /* Reallocate the linear memory */
342
343     ptr = (void *)pArena->base;
344     oldsize = pArena->size;
345     TRACE("oldbase %p oldsize %08lx newsize %08lx\n", ptr,oldsize,size);
346     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
347
348     if (pArena->flags & GA_DOSMEM)
349     {
350         if (DOSMEM_ResizeBlock(ptr, size, TRUE) == size) 
351             newptr = ptr;
352         else if(pArena->pageLockCount > 0)
353             newptr = 0;
354         else
355         {
356             newptr = DOSMEM_GetBlock( size, 0 );
357             if (newptr)
358             {
359                 memcpy( newptr, ptr, oldsize );
360                 DOSMEM_FreeBlock( ptr );
361             }
362         }
363     }
364     else
365     {
366         /*
367          * if more than one reader (e.g. some pointer has been 
368          * given out by GetVDMPointer32W16),
369          * only try to realloc in place
370          */
371         newptr = HeapReAlloc( GetProcessHeap(),
372                               (pArena->pageLockCount > 0) ? 
373                               HEAP_REALLOC_IN_PLACE_ONLY : 0, 
374                               ptr, size );
375     }
376
377     if (!newptr)
378     {
379         FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
380         if (pArena->pageLockCount <1)
381         {
382             if (pArena->flags & GA_DOSMEM)
383                 DOSMEM_FreeBlock( (void *)pArena->base );
384             else
385                 HeapFree( GetProcessHeap(), 0, ptr );
386             SELECTOR_FreeBlock( sel );
387             memset( pArena, 0, sizeof(GLOBALARENA) );
388         }
389         return 0;
390     }
391     ptr = newptr;
392
393       /* Reallocate the selector(s) */
394
395     sel = SELECTOR_ReallocBlock( sel, ptr, size );
396     if (!sel)
397     {
398         if (pArena->flags & GA_DOSMEM)
399             DOSMEM_FreeBlock( (void *)pArena->base );
400         else
401             HeapFree( GetProcessHeap(), 0, ptr );
402         memset( pArena, 0, sizeof(GLOBALARENA) );
403         return 0;
404     }
405     selcount = (size + 0xffff) / 0x10000;
406
407     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
408     {        
409         if (pArena->flags & GA_DOSMEM)
410             DOSMEM_FreeBlock( (void *)pArena->base );
411         else
412             HeapFree( GetProcessHeap(), 0, ptr );
413         SELECTOR_FreeBlock( sel );
414         return 0;
415     }
416
417       /* Fill the new arena block
418          As we may have used HEAP_REALLOC_IN_PLACE_ONLY, areas may overlap*/
419
420     if (pNewArena != pArena) memmove( pNewArena, pArena, sizeof(GLOBALARENA) );
421     pNewArena->base = (DWORD)ptr;
422     pNewArena->size = GetSelectorLimit16(sel) + 1;
423     pNewArena->selCount = selcount;
424     pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
425
426     if (selcount > 1)  /* clear the next arena blocks */
427         memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
428
429     if ((oldsize < size) && (flags & GMEM_ZEROINIT))
430         memset( (char *)ptr + oldsize, 0, size - oldsize );
431     return pNewArena->handle;
432 }
433
434
435 /***********************************************************************
436  *           GlobalFree     (KERNEL.17)
437  *           GlobalFree16   (KERNEL32.31)
438  * RETURNS
439  *      NULL: Success
440  *      Handle: Failure
441  */
442 HGLOBAL16 WINAPI GlobalFree16(
443                  HGLOBAL16 handle /* [in] Handle of global memory object */
444 ) {
445     void *ptr;
446
447     if (!VALID_HANDLE(handle)) {
448         WARN("Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
449         return 0;
450     }
451     ptr = (void *)GET_ARENA_PTR(handle)->base;
452
453     TRACE("%04x\n", handle );
454     if (!GLOBAL_FreeBlock( handle )) return handle;  /* failed */
455     if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
456     return 0;
457 }
458
459
460 /***********************************************************************
461  *           GlobalLock   (KERNEL.18)
462  *
463  * This is the GlobalLock16() function used by 16-bit code.
464  */
465 SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
466 {
467     WORD sel = GlobalHandleToSel16( handle );
468     TRACE("(%04x) -> %08lx\n", handle, MAKELONG( 0, sel ) );
469
470     if (handle)
471     {
472         if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
473
474         if (!VALID_HANDLE(handle)) {
475             WARN("Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
476             sel = 0;
477         }
478         else if (!GET_ARENA_PTR(handle)->base)
479             sel = 0;
480         else
481             GET_ARENA_PTR(handle)->lockCount++;
482     }
483
484     CURRENT_STACK16->ecx = sel;  /* selector must be returned in CX as well */
485     return MAKESEGPTR( sel, 0 );
486 }
487
488
489 /**********************************************************************
490  *           K32WOWGlobalLock16         (KERNEL32.60)
491  */
492 SEGPTR WINAPI K32WOWGlobalLock16( HGLOBAL16 hMem )
493 {
494     return WIN16_GlobalLock16( hMem );
495 }
496
497
498 /***********************************************************************
499  *           GlobalLock16   (KERNEL32.25)
500  *
501  * This is the GlobalLock16() function used by 32-bit code.
502  *
503  * RETURNS
504  *      Pointer to first byte of memory block
505  *      NULL: Failure
506  */
507 LPVOID WINAPI GlobalLock16(
508               HGLOBAL16 handle /* [in] Handle of global memory object */
509 ) {
510     if (!handle) return 0;
511     if (!VALID_HANDLE(handle))
512         return 0;
513     GET_ARENA_PTR(handle)->lockCount++;
514     return (LPVOID)GET_ARENA_PTR(handle)->base;
515 }
516
517
518 /***********************************************************************
519  *           GlobalUnlock     (KERNEL.19)
520  *           GlobalUnlock16   (KERNEL32.26)
521  * NOTES
522  *      Should the return values be cast to booleans?
523  *
524  * RETURNS
525  *      TRUE: Object is still locked
526  *      FALSE: Object is unlocked
527  */
528 BOOL16 WINAPI GlobalUnlock16(
529               HGLOBAL16 handle /* [in] Handle of global memory object */
530 ) {
531     GLOBALARENA *pArena = GET_ARENA_PTR(handle);
532     if (!VALID_HANDLE(handle)) {
533         WARN("Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
534         return 0;
535     }
536     TRACE("%04x\n", handle );
537     if (pArena->lockCount) pArena->lockCount--;
538     return pArena->lockCount;
539 }
540
541 /***********************************************************************
542  *     GlobalChangeLockCount               (KERNEL.365)
543  *
544  * This is declared as a register function as it has to preserve
545  * *all* registers, even AX/DX !
546  *
547  */
548 void WINAPI GlobalChangeLockCount16( HGLOBAL16 handle, INT16 delta,
549                                      CONTEXT86 *context )
550 {
551     if ( delta == 1 )
552         GlobalLock16( handle );
553     else if ( delta == -1 )
554         GlobalUnlock16( handle );
555     else
556         ERR("(%04X, %d): strange delta value\n", handle, delta );
557 }
558
559 /***********************************************************************
560  *           GlobalSize     (KERNEL.20)
561  *           GlobalSize16   (KERNEL32.32)
562  * RETURNS
563  *      Size in bytes of object
564  *      0: Failure
565  */
566 DWORD WINAPI GlobalSize16(
567              HGLOBAL16 handle /* [in] Handle of global memory object */
568 ) {
569     TRACE("%04x\n", handle );
570     if (!handle) return 0;
571     if (!VALID_HANDLE(handle))
572         return 0;
573     return GET_ARENA_PTR(handle)->size;
574 }
575
576
577 /***********************************************************************
578  *           GlobalHandle   (KERNEL.21)
579  * NOTES
580  *      Why is GlobalHandleToSel used here with the sel as input?
581  *
582  * RETURNS
583  *      Handle: Success
584  *      NULL: Failure
585  */
586 DWORD WINAPI GlobalHandle16(
587              WORD sel /* [in] Address of global memory block */
588 ) {
589     TRACE("%04x\n", sel );
590     if (!VALID_HANDLE(sel)) {
591         WARN("Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
592         return 0;
593     }
594     return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
595 }
596
597 /***********************************************************************
598  *           GlobalHandleNoRIP   (KERNEL.159)
599  */
600 DWORD WINAPI GlobalHandleNoRIP16( WORD sel )
601 {
602     int i;
603     for (i = globalArenaSize-1 ; i>=0 ; i--) {
604         if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
605                 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
606     }
607     return 0;
608 }
609
610
611 /***********************************************************************
612  *           GlobalFlags     (KERNEL.22)
613  *
614  * NOTES
615  *      Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
616  *      handle?
617  *
618  * RETURNS
619  *      Value specifying flags and lock count
620  *      GMEM_INVALID_HANDLE: Invalid handle
621  */
622 UINT16 WINAPI GlobalFlags16(
623               HGLOBAL16 handle /* [in] Handle of global memory object */
624 ) {
625     GLOBALARENA *pArena;
626
627     TRACE("%04x\n", handle );
628     if (!VALID_HANDLE(handle)) {
629         WARN("Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
630         return 0;
631     }
632     pArena = GET_ARENA_PTR(handle);
633     return pArena->lockCount |
634            ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
635            ((pArena->base == 0) ? GMEM_DISCARDED : 0);
636 }
637
638
639 /***********************************************************************
640  *           LockSegment   (KERNEL.23)
641  */
642 HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
643 {
644     TRACE("%04x\n", handle );
645     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
646     if (!VALID_HANDLE(handle)) {
647         WARN("Invalid handle 0x%04x passed to LockSegment16!\n",handle);
648         return 0;
649     }
650     GET_ARENA_PTR(handle)->lockCount++;
651     return handle;
652 }
653
654
655 /***********************************************************************
656  *           UnlockSegment   (KERNEL.24)
657  */
658 void WINAPI UnlockSegment16( HGLOBAL16 handle )
659 {
660     TRACE("%04x\n", handle );
661     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
662     if (!VALID_HANDLE(handle)) {
663         WARN("Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
664         return;
665     }
666     GET_ARENA_PTR(handle)->lockCount--;
667     /* FIXME: this ought to return the lock count in CX (go figure...) */
668 }
669
670
671 /***********************************************************************
672  *           GlobalCompact   (KERNEL.25)
673  */
674 DWORD WINAPI GlobalCompact16( DWORD desired )
675 {
676     return GLOBAL_MAX_ALLOC_SIZE;
677 }
678
679
680 /***********************************************************************
681  *           GlobalFreeAll   (KERNEL.26)
682  */
683 void WINAPI GlobalFreeAll16( HGLOBAL16 owner )
684 {
685     DWORD i;
686     GLOBALARENA *pArena;
687
688     pArena = pGlobalArena;
689     for (i = 0; i < globalArenaSize; i++, pArena++)
690     {
691         if ((pArena->size != 0) && (pArena->hOwner == owner))
692             GlobalFree16( pArena->handle );
693     }
694 }
695
696
697 /***********************************************************************
698  *           GlobalWire     (KERNEL.111)
699  *           GlobalWire16   (KERNEL32.29)
700  */
701 SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
702 {
703     return WIN16_GlobalLock16( handle );
704 }
705
706
707 /***********************************************************************
708  *           GlobalUnWire     (KERNEL.112)
709  *           GlobalUnWire16   (KERNEL32.30)
710  */
711 BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
712 {
713     return !GlobalUnlock16( handle );
714 }
715
716
717 /***********************************************************************
718  *           SetSwapAreaSize   (KERNEL.106)
719  */
720 LONG WINAPI SetSwapAreaSize16( WORD size )
721 {
722     FIXME("(%d) - stub!\n", size );
723     return MAKELONG( size, 0xffff );
724 }
725
726
727 /***********************************************************************
728  *           GlobalLRUOldest   (KERNEL.163)
729  */
730 HGLOBAL16 WINAPI GlobalLRUOldest16( HGLOBAL16 handle )
731 {
732     TRACE("%04x\n", handle );
733     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
734     return handle;
735 }
736
737
738 /***********************************************************************
739  *           GlobalLRUNewest   (KERNEL.164)
740  */
741 HGLOBAL16 WINAPI GlobalLRUNewest16( HGLOBAL16 handle )
742 {
743     TRACE("%04x\n", handle );
744     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
745     return handle;
746 }
747
748
749 /***********************************************************************
750  *           GetFreeSpace   (KERNEL.169)
751  */
752 DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
753 {
754     MEMORYSTATUS ms;
755     GlobalMemoryStatus( &ms );
756     return ms.dwAvailVirtual;
757 }
758
759 /***********************************************************************
760  *           GlobalDOSAlloc   (KERNEL.184)
761  * RETURNS
762  *      Address (HW=Paragraph segment; LW=Selector)
763  */
764 DWORD WINAPI GlobalDOSAlloc16(
765              DWORD size /* [in] Number of bytes to be allocated */
766 ) {
767    UINT16    uParagraph;
768    LPVOID    lpBlock = DOSMEM_GetBlock( size, &uParagraph );
769
770    if( lpBlock )
771    {
772        HMODULE16 hModule = GetModuleHandle16("KERNEL");
773        WORD      wSelector;
774        GLOBALARENA *pArena;
775
776        wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, hModule, WINE_LDT_FLAGS_DATA );
777        pArena = GET_ARENA_PTR(wSelector);
778        pArena->flags |= GA_DOSMEM;
779        return MAKELONG(wSelector,uParagraph);
780    }
781    return 0;
782 }
783
784
785 /***********************************************************************
786  *           GlobalDOSFree      (KERNEL.185)
787  * RETURNS
788  *      NULL: Success
789  *      sel: Failure
790  */
791 WORD WINAPI GlobalDOSFree16(
792             WORD sel /* [in] Selector */
793 ) {
794    DWORD   block = GetSelectorBase(sel);
795
796    if( block && block < 0x100000 )
797    {
798        LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
799        if( DOSMEM_FreeBlock( lpBlock ) )
800            GLOBAL_FreeBlock( sel );
801        sel = 0;
802    }
803    return sel;
804 }
805
806
807 /***********************************************************************
808  *           GlobalPageLock   (KERNEL.191)
809  *           GlobalSmartPageLock(KERNEL.230)
810  */
811 WORD WINAPI GlobalPageLock16( HGLOBAL16 handle )
812 {
813     TRACE("%04x\n", handle );
814     if (!VALID_HANDLE(handle)) {
815         WARN("Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
816         return 0;
817     }
818     return ++(GET_ARENA_PTR(handle)->pageLockCount);
819 }
820
821
822 /***********************************************************************
823  *           GlobalPageUnlock   (KERNEL.192)
824  *           GlobalSmartPageUnlock(KERNEL.231)
825  */
826 WORD WINAPI GlobalPageUnlock16( HGLOBAL16 handle )
827 {
828     TRACE("%04x\n", handle );
829     if (!VALID_HANDLE(handle)) {
830         WARN("Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
831         return 0;
832     }
833     return --(GET_ARENA_PTR(handle)->pageLockCount);
834 }
835
836
837 /***********************************************************************
838  *           GlobalFix     (KERNEL.197)
839  *           GlobalFix16   (KERNEL32.27)
840  */
841 WORD WINAPI GlobalFix16( HGLOBAL16 handle )
842 {
843     TRACE("%04x\n", handle );
844     if (!VALID_HANDLE(handle)) {
845         WARN("Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
846         return 0;
847     }
848     GET_ARENA_PTR(handle)->lockCount++;
849
850     return GlobalHandleToSel16(handle);
851 }
852
853
854 /***********************************************************************
855  *           GlobalUnfix     (KERNEL.198)
856  *           GlobalUnfix16   (KERNEL32.28)
857  */
858 void WINAPI GlobalUnfix16( HGLOBAL16 handle )
859 {
860     TRACE("%04x\n", handle );
861     if (!VALID_HANDLE(handle)) {
862         WARN("Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
863         return;
864     }
865     GET_ARENA_PTR(handle)->lockCount--;
866 }
867
868
869 /***********************************************************************
870  *           FarSetOwner   (KERNEL.403)
871  */
872 void WINAPI FarSetOwner16( HGLOBAL16 handle, HANDLE16 hOwner )
873 {
874     if (!VALID_HANDLE(handle)) {
875         WARN("Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
876         return;
877     }
878     GET_ARENA_PTR(handle)->hOwner = hOwner;
879 }
880
881
882 /***********************************************************************
883  *           FarGetOwner   (KERNEL.404)
884  */
885 HANDLE16 WINAPI FarGetOwner16( HGLOBAL16 handle )
886 {
887     if (!VALID_HANDLE(handle)) {
888         WARN("Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
889         return 0;
890     }
891     return GET_ARENA_PTR(handle)->hOwner;
892 }
893
894
895 /***********************************************************************
896  *           GlobalHandleToSel   (TOOLHELP.50)
897  */
898 WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
899 {
900     if (!handle) return 0;
901     if (!VALID_HANDLE(handle)) {
902         WARN("Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
903         return 0;
904     }
905     if (!(handle & 7))
906     {
907         WARN("Program attempted invalid selector conversion\n" );
908         return handle - 1;
909     }
910     return handle | 7;
911 }
912
913
914 /***********************************************************************
915  *           GlobalFirst   (TOOLHELP.51)
916  */
917 BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
918 {
919     if (wFlags == GLOBAL_LRU) return FALSE;
920     pGlobal->dwNext = 0;
921     return GlobalNext16( pGlobal, wFlags );
922 }
923
924
925 /***********************************************************************
926  *           GlobalNext   (TOOLHELP.52)
927  */
928 BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
929 {
930     GLOBALARENA *pArena;
931
932     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
933     pArena = pGlobalArena + pGlobal->dwNext;
934     if (wFlags == GLOBAL_FREE)  /* only free blocks */
935     {
936         int i;
937         for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
938             if (pArena->size == 0) break;  /* block is free */
939         if (i >= globalArenaSize) return FALSE;
940         pGlobal->dwNext = i;
941     }
942
943     pGlobal->dwAddress    = pArena->base;
944     pGlobal->dwBlockSize  = pArena->size;
945     pGlobal->hBlock       = pArena->handle;
946     pGlobal->wcLock       = pArena->lockCount;
947     pGlobal->wcPageLock   = pArena->pageLockCount;
948     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
949     pGlobal->wHeapPresent = FALSE;
950     pGlobal->hOwner       = pArena->hOwner;
951     pGlobal->wType        = GT_UNKNOWN;
952     pGlobal->wData        = 0;
953     pGlobal->dwNext++;
954     return TRUE;
955 }
956
957
958 /***********************************************************************
959  *           GlobalInfo   (TOOLHELP.53)
960  */
961 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
962 {
963     int i;
964     GLOBALARENA *pArena;
965
966     pInfo->wcItems = globalArenaSize;
967     pInfo->wcItemsFree = 0;
968     pInfo->wcItemsLRU = 0;
969     for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
970         if (pArena->size == 0) pInfo->wcItemsFree++;
971     return TRUE;
972 }
973
974
975 /***********************************************************************
976  *           GlobalEntryHandle   (TOOLHELP.54)
977  */
978 BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
979 {
980     GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
981
982     pGlobal->dwAddress    = pArena->base;
983     pGlobal->dwBlockSize  = pArena->size;
984     pGlobal->hBlock       = pArena->handle;
985     pGlobal->wcLock       = pArena->lockCount;
986     pGlobal->wcPageLock   = pArena->pageLockCount;
987     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
988     pGlobal->wHeapPresent = FALSE;
989     pGlobal->hOwner       = pArena->hOwner;
990     pGlobal->wType        = GT_UNKNOWN;
991     pGlobal->wData        = 0;
992     pGlobal->dwNext++;
993     return TRUE;
994 }
995
996
997 /***********************************************************************
998  *           GlobalEntryModule   (TOOLHELP.55)
999  */
1000 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
1001                                  WORD wSeg )
1002 {
1003     FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
1004     return FALSE;
1005 }
1006
1007
1008 /***********************************************************************
1009  *           MemManInfo   (TOOLHELP.72)
1010  */
1011 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
1012 {
1013     MEMORYSTATUS status;
1014
1015     /*
1016      * Not unsurprisingly although the documention says you
1017      * _must_ provide the size in the dwSize field, this function
1018      * (under Windows) always fills the structure and returns true.
1019      */
1020     GlobalMemoryStatus( &status );
1021     info->wPageSize            = getpagesize();
1022     info->dwLargestFreeBlock   = status.dwAvailVirtual;
1023     info->dwMaxPagesAvailable  = info->dwLargestFreeBlock / info->wPageSize;
1024     info->dwMaxPagesLockable   = info->dwMaxPagesAvailable;
1025     info->dwTotalLinearSpace   = status.dwTotalVirtual / info->wPageSize;
1026     info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
1027     info->dwFreePages          = info->dwMaxPagesAvailable;
1028     info->dwTotalPages         = info->dwTotalLinearSpace;
1029     info->dwFreeLinearSpace    = info->dwMaxPagesAvailable;
1030     info->dwSwapFilePages      = status.dwTotalPageFile / info->wPageSize;
1031     return TRUE;
1032 }
1033
1034 /***********************************************************************
1035  *           GetFreeMemInfo   (KERNEL.316)
1036  */
1037 DWORD WINAPI GetFreeMemInfo16(void)
1038 {
1039     MEMMANINFO info;
1040     MemManInfo16( &info );
1041     return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
1042 }
1043
1044 /*
1045  * Win32 Global heap functions (GlobalXXX).
1046  * These functions included in Win32 for compatibility with 16 bit Windows
1047  * Especially the moveable blocks and handles are oldish.
1048  * But the ability to directly allocate memory with GPTR and LPTR is widely
1049  * used.
1050  *
1051  * The handle stuff looks horrible, but it's implemented almost like Win95
1052  * does it.
1053  *
1054  */
1055
1056 #define MAGIC_GLOBAL_USED 0x5342
1057 #define GLOBAL_LOCK_MAX   0xFF
1058 #define HANDLE_TO_INTERN(h)  ((PGLOBAL32_INTERN)(((char *)(h))-2))
1059 #define INTERN_TO_HANDLE(i)  ((HGLOBAL) &((i)->Pointer))
1060 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL *)(p))-2))
1061 #define ISHANDLE(h)          (((ULONG_PTR)(h)&2)!=0)
1062 #define ISPOINTER(h)         (((ULONG_PTR)(h)&2)==0)
1063 /* align the storage needed for the HGLOBAL on an 8byte boundary thus
1064  * GlobalAlloc/GlobalReAlloc'ing with GMEM_MOVEABLE of memory with
1065  * size = 8*k, where k=1,2,3,... alloc's exactly the given size.
1066  * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
1067  * the output jpeg's > 1 MB if not */
1068 #define HGLOBAL_STORAGE      8  /* sizeof(HGLOBAL)*2 */
1069
1070 typedef struct __GLOBAL32_INTERN
1071 {
1072    WORD         Magic;
1073    LPVOID       Pointer WINE_PACKED;
1074    BYTE         Flags;
1075    BYTE         LockCount;
1076 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
1077
1078
1079 /***********************************************************************
1080  *           GlobalAlloc   (KERNEL32.@)
1081  * RETURNS
1082  *      Handle: Success
1083  *      NULL: Failure
1084  */
1085 HGLOBAL WINAPI GlobalAlloc(
1086                  UINT flags, /* [in] Object allocation attributes */
1087                  SIZE_T size /* [in] Number of bytes to allocate */
1088 ) {
1089    PGLOBAL32_INTERN     pintern;
1090    DWORD                hpflags;
1091    LPVOID               palloc;
1092
1093    if(flags&GMEM_ZEROINIT)
1094       hpflags=HEAP_ZERO_MEMORY;
1095    else
1096       hpflags=0;
1097
1098    TRACE("() flags=%04x\n",  flags );
1099
1100    if((flags & GMEM_MOVEABLE)==0) /* POINTER */
1101    {
1102       palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
1103       return (HGLOBAL) palloc;
1104    }
1105    else  /* HANDLE */
1106    {
1107       RtlLockHeap(GetProcessHeap());
1108
1109       pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
1110       if (pintern)
1111       {
1112           pintern->Magic = MAGIC_GLOBAL_USED;
1113           pintern->Flags = flags >> 8;
1114           pintern->LockCount = 0;
1115
1116           if (size)
1117           {
1118               palloc = HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE);
1119               if (!palloc)
1120               {
1121                   HeapFree(GetProcessHeap(), 0, pintern);
1122                   pintern = NULL;
1123               }
1124               else
1125               {
1126                   *(HGLOBAL *)palloc = INTERN_TO_HANDLE(pintern);
1127                   pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
1128               }
1129           }
1130           else
1131               pintern->Pointer = NULL;
1132       }
1133
1134       RtlUnlockHeap(GetProcessHeap());
1135       return pintern ? INTERN_TO_HANDLE(pintern) : 0;
1136    }
1137 }
1138
1139
1140 /***********************************************************************
1141  *           GlobalLock   (KERNEL32.@)
1142  * RETURNS
1143  *      Pointer to first byte of block
1144  *      NULL: Failure
1145  */
1146 LPVOID WINAPI GlobalLock(
1147               HGLOBAL hmem /* [in] Handle of global memory object */
1148 )
1149 {
1150     PGLOBAL32_INTERN pintern;
1151     LPVOID           palloc;
1152
1153     if (ISPOINTER(hmem))
1154         return IsBadReadPtr(hmem, 1) ? NULL : hmem;
1155
1156     RtlLockHeap(GetProcessHeap());
1157     __TRY
1158     {
1159         pintern = HANDLE_TO_INTERN(hmem);
1160         if (pintern->Magic == MAGIC_GLOBAL_USED)
1161         {
1162             if (pintern->LockCount < GLOBAL_LOCK_MAX)
1163                 pintern->LockCount++;
1164             palloc = pintern->Pointer;
1165         }
1166         else
1167         {
1168             WARN("invalid handle %p\n", hmem);
1169             palloc = NULL;
1170             SetLastError(ERROR_INVALID_HANDLE);
1171         }
1172     }
1173     __EXCEPT(page_fault)
1174     {
1175         WARN("page fault on %p\n", hmem);
1176         palloc = NULL;
1177         SetLastError(ERROR_INVALID_HANDLE);
1178     }
1179     __ENDTRY
1180     RtlUnlockHeap(GetProcessHeap());
1181     return palloc;
1182 }
1183
1184
1185 /***********************************************************************
1186  *           GlobalUnlock   (KERNEL32.@)
1187  * RETURNS
1188  *      TRUE: Object is still locked
1189  *      FALSE: Object is unlocked
1190  */
1191 BOOL WINAPI GlobalUnlock(
1192               HGLOBAL hmem /* [in] Handle of global memory object */
1193 ) {
1194     PGLOBAL32_INTERN pintern;
1195     BOOL locked;
1196
1197     if (ISPOINTER(hmem)) return FALSE;
1198
1199     RtlLockHeap(GetProcessHeap());
1200     __TRY
1201     {
1202         pintern=HANDLE_TO_INTERN(hmem);
1203         if(pintern->Magic==MAGIC_GLOBAL_USED)
1204         {
1205             if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
1206                 pintern->LockCount--;
1207
1208             locked = (pintern->LockCount != 0);
1209             if (!locked) SetLastError(NO_ERROR);
1210         }
1211         else
1212         {
1213             WARN("invalid handle\n");
1214             SetLastError(ERROR_INVALID_HANDLE);
1215             locked=FALSE;
1216         }
1217     }
1218     __EXCEPT(page_fault)
1219     {
1220         ERR("page fault occurred ! Caused by bug ?\n");
1221         SetLastError( ERROR_INVALID_PARAMETER );
1222         locked=FALSE;
1223     }
1224     __ENDTRY
1225     RtlUnlockHeap(GetProcessHeap());
1226     return locked;
1227 }
1228
1229
1230 /***********************************************************************
1231  *           GlobalHandle   (KERNEL32.@)
1232  * Returns the handle associated with the specified pointer.
1233  *
1234  * RETURNS
1235  *      Handle: Success
1236  *      NULL: Failure
1237  */
1238 HGLOBAL WINAPI GlobalHandle(
1239                  LPCVOID pmem /* [in] Pointer to global memory block */
1240 ) {
1241     HGLOBAL handle;
1242     PGLOBAL32_INTERN  maybe_intern;
1243     LPCVOID test;
1244
1245     if (!pmem)
1246     {
1247         SetLastError( ERROR_INVALID_PARAMETER );
1248         return 0;
1249     }
1250
1251     RtlLockHeap(GetProcessHeap());
1252     __TRY
1253     {
1254         handle = 0;
1255
1256         /* note that if pmem is a pointer to a a block allocated by        */
1257         /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate  */
1258         /* will fail.                                                      */
1259         if (ISPOINTER(pmem)) {
1260             if (HeapValidate( GetProcessHeap(), 0, pmem )) {
1261                 handle = (HGLOBAL)pmem;  /* valid fixed block */
1262                 break;
1263             }
1264             handle = POINTER_TO_HANDLE(pmem);
1265         } else
1266             handle = (HGLOBAL)pmem;
1267
1268         /* Now test handle either passed in or retrieved from pointer */
1269         maybe_intern = HANDLE_TO_INTERN( handle );
1270         if (maybe_intern->Magic == MAGIC_GLOBAL_USED) {
1271             test = maybe_intern->Pointer;
1272             if (HeapValidate( GetProcessHeap(), 0, (char *)test - HGLOBAL_STORAGE ) && /* obj(-handle) valid arena? */
1273                 HeapValidate( GetProcessHeap(), 0, maybe_intern ))  /* intern valid arena? */
1274                 break;  /* valid moveable block */
1275         }
1276         handle = 0;
1277         SetLastError( ERROR_INVALID_HANDLE );
1278     }
1279     __EXCEPT(page_fault)
1280     {
1281         SetLastError( ERROR_INVALID_HANDLE );
1282         handle = 0;
1283     }
1284     __ENDTRY
1285     RtlUnlockHeap(GetProcessHeap());
1286
1287     return handle;
1288 }
1289
1290
1291 /***********************************************************************
1292  *           GlobalReAlloc   (KERNEL32.@)
1293  * RETURNS
1294  *      Handle: Success
1295  *      NULL: Failure
1296  */
1297 HGLOBAL WINAPI GlobalReAlloc(
1298                  HGLOBAL hmem, /* [in] Handle of global memory object */
1299                  SIZE_T size,  /* [in] New size of block */
1300                  UINT flags    /* [in] How to reallocate object */
1301 ) {
1302    LPVOID               palloc;
1303    HGLOBAL            hnew;
1304    PGLOBAL32_INTERN     pintern;
1305    DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
1306
1307    hnew = 0;
1308    RtlLockHeap(GetProcessHeap());
1309    if(flags & GMEM_MODIFY) /* modify flags */
1310    {
1311       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
1312       {
1313          /* make a fixed block moveable
1314           * actually only NT is able to do this. But it's soo simple
1315           */
1316          if (hmem == 0)
1317          {
1318              WARN("GlobalReAlloc with null handle!\n");
1319              SetLastError( ERROR_NOACCESS );
1320              hnew = 0;
1321          }
1322          else
1323          {
1324              size = HeapSize(GetProcessHeap(), 0, (LPVOID)hmem);
1325              hnew = GlobalAlloc(flags, size);
1326              palloc = GlobalLock(hnew);
1327              memcpy(palloc, (LPVOID)hmem, size);
1328              GlobalUnlock(hnew);
1329              GlobalFree(hmem);
1330          }
1331       }
1332       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
1333       {
1334          /* change the flags to make our block "discardable" */
1335          pintern=HANDLE_TO_INTERN(hmem);
1336          pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
1337          hnew=hmem;
1338       }
1339       else
1340       {
1341          SetLastError(ERROR_INVALID_PARAMETER);
1342          hnew = 0;
1343       }
1344    }
1345    else
1346    {
1347       if(ISPOINTER(hmem))
1348       {
1349          /* reallocate fixed memory */
1350          hnew=(HGLOBAL)HeapReAlloc(GetProcessHeap(), heap_flags, (LPVOID) hmem, size);
1351       }
1352       else
1353       {
1354          /* reallocate a moveable block */
1355          pintern=HANDLE_TO_INTERN(hmem);
1356
1357 #if 0
1358 /* Apparently Windows doesn't care whether the handle is locked at this point */
1359 /* See also the same comment in GlobalFree() */
1360          if(pintern->LockCount>1) {
1361             ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
1362             SetLastError(ERROR_INVALID_HANDLE);
1363          } else
1364 #endif
1365          if(size!=0)
1366          {
1367             hnew=hmem;
1368             if(pintern->Pointer)
1369             {
1370                if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags,
1371                                    (char *) pintern->Pointer-HGLOBAL_STORAGE,
1372                                    size+HGLOBAL_STORAGE)) == NULL)
1373                    hnew = 0; /* Block still valid */
1374                else
1375                    pintern->Pointer = (char *)palloc+HGLOBAL_STORAGE;
1376             }
1377             else
1378             {
1379                 if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE))
1380                    == NULL)
1381                     hnew = 0;
1382                 else
1383                 {
1384                     *(HGLOBAL *)palloc = hmem;
1385                     pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
1386                 }
1387             }
1388          }
1389          else
1390          {
1391             if(pintern->Pointer)
1392             {
1393                HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE);
1394                pintern->Pointer=NULL;
1395             }
1396          }
1397       }
1398    }
1399    RtlUnlockHeap(GetProcessHeap());
1400    return hnew;
1401 }
1402
1403
1404 /***********************************************************************
1405  *           GlobalFree   (KERNEL32.@)
1406  * RETURNS
1407  *      NULL: Success
1408  *      Handle: Failure
1409  */
1410 HGLOBAL WINAPI GlobalFree(
1411                  HGLOBAL hmem /* [in] Handle of global memory object */
1412 ) {
1413     PGLOBAL32_INTERN pintern;
1414     HGLOBAL hreturned;
1415
1416     RtlLockHeap(GetProcessHeap());
1417     __TRY
1418     {
1419         hreturned = 0;
1420         if(ISPOINTER(hmem)) /* POINTER */
1421         {
1422             if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
1423         }
1424         else  /* HANDLE */
1425         {
1426             pintern=HANDLE_TO_INTERN(hmem);
1427
1428             if(pintern->Magic==MAGIC_GLOBAL_USED)
1429             {
1430
1431                 /* WIN98 does not make this test. That is you can free a */
1432                 /* block you have not unlocked. Go figure!!              */
1433                 /* if(pintern->LockCount!=0)  */
1434                 /*    SetLastError(ERROR_INVALID_HANDLE);  */
1435
1436                 if(pintern->Pointer)
1437                     if(!HeapFree(GetProcessHeap(), 0, (char *)(pintern->Pointer)-HGLOBAL_STORAGE))
1438                         hreturned=hmem;
1439                 if(!HeapFree(GetProcessHeap(), 0, pintern))
1440                     hreturned=hmem;
1441             }
1442         }
1443     }
1444     __EXCEPT(page_fault)
1445     {
1446         ERR("page fault occurred ! Caused by bug ?\n");
1447         SetLastError( ERROR_INVALID_PARAMETER );
1448         hreturned = hmem;
1449     }
1450     __ENDTRY
1451     RtlUnlockHeap(GetProcessHeap());
1452     return hreturned;
1453 }
1454
1455
1456 /***********************************************************************
1457  *           GlobalSize   (KERNEL32.@)
1458  * RETURNS
1459  *      Size in bytes of the global memory object
1460  *      0: Failure
1461  */
1462 SIZE_T WINAPI GlobalSize(
1463              HGLOBAL hmem /* [in] Handle of global memory object */
1464 ) {
1465    DWORD                retval;
1466    PGLOBAL32_INTERN     pintern;
1467
1468    if (!hmem) return 0;
1469
1470    if(ISPOINTER(hmem))
1471    {
1472       retval=HeapSize(GetProcessHeap(), 0,  (LPVOID) hmem);
1473    }
1474    else
1475    {
1476       RtlLockHeap(GetProcessHeap());
1477       pintern=HANDLE_TO_INTERN(hmem);
1478
1479       if(pintern->Magic==MAGIC_GLOBAL_USED)
1480       {
1481          if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */
1482              retval = 0;
1483          else
1484          {
1485              retval = HeapSize(GetProcessHeap(), 0,
1486                          (char *)(pintern->Pointer) - HGLOBAL_STORAGE );
1487              if (retval != (DWORD)-1) retval -= HGLOBAL_STORAGE;
1488          }
1489       }
1490       else
1491       {
1492          WARN("invalid handle\n");
1493          retval=0;
1494       }
1495       RtlUnlockHeap(GetProcessHeap());
1496    }
1497    /* HeapSize returns 0xffffffff on failure */
1498    if (retval == 0xffffffff) retval = 0;
1499    return retval;
1500 }
1501
1502
1503 /***********************************************************************
1504  *           GlobalWire   (KERNEL32.@)
1505  */
1506 LPVOID WINAPI GlobalWire(HGLOBAL hmem)
1507 {
1508    return GlobalLock( hmem );
1509 }
1510
1511
1512 /***********************************************************************
1513  *           GlobalUnWire   (KERNEL32.@)
1514  */
1515 BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
1516 {
1517    return GlobalUnlock( hmem);
1518 }
1519
1520
1521 /***********************************************************************
1522  *           GlobalFix   (KERNEL32.@)
1523  */
1524 VOID WINAPI GlobalFix(HGLOBAL hmem)
1525 {
1526     GlobalLock( hmem );
1527 }
1528
1529
1530 /***********************************************************************
1531  *           GlobalUnfix   (KERNEL32.@)
1532  */
1533 VOID WINAPI GlobalUnfix(HGLOBAL hmem)
1534 {
1535    GlobalUnlock( hmem);
1536 }
1537
1538
1539 /***********************************************************************
1540  *           GlobalFlags   (KERNEL32.@)
1541  * Returns information about the specified global memory object
1542  *
1543  * NOTES
1544  *      Should this return GMEM_INVALID_HANDLE on invalid handle?
1545  *
1546  * RETURNS
1547  *      Value specifying allocation flags and lock count
1548  *      GMEM_INVALID_HANDLE: Failure
1549  */
1550 UINT WINAPI GlobalFlags(
1551               HGLOBAL hmem /* [in] Handle to global memory object */
1552 ) {
1553    DWORD                retval;
1554    PGLOBAL32_INTERN     pintern;
1555
1556    if(ISPOINTER(hmem))
1557    {
1558       retval=0;
1559    }
1560    else
1561    {
1562       RtlLockHeap(GetProcessHeap());
1563       pintern=HANDLE_TO_INTERN(hmem);
1564       if(pintern->Magic==MAGIC_GLOBAL_USED)
1565       {
1566          retval=pintern->LockCount + (pintern->Flags<<8);
1567          if(pintern->Pointer==0)
1568             retval|= GMEM_DISCARDED;
1569       }
1570       else
1571       {
1572          WARN("Invalid handle: %p\n", hmem);
1573          retval=0;
1574       }
1575       RtlUnlockHeap(GetProcessHeap());
1576    }
1577    return retval;
1578 }
1579
1580
1581 /***********************************************************************
1582  *           GlobalCompact   (KERNEL32.@)
1583  */
1584 SIZE_T WINAPI GlobalCompact( DWORD minfree )
1585 {
1586     return 0;  /* GlobalCompact does nothing in Win32 */
1587 }
1588
1589
1590 /***********************************************************************
1591  *           GlobalMemoryStatus   (KERNEL32.@)
1592  * Provides information about the status of the memory, so apps can tell
1593  * roughly how much they are able to allocate
1594  * 
1595  * RETURNS
1596  *      None
1597  */
1598 VOID WINAPI GlobalMemoryStatus(
1599             LPMEMORYSTATUS lpmem
1600 ) {
1601     static MEMORYSTATUS cached_memstatus;
1602     static int cache_lastchecked = 0;
1603     SYSTEM_INFO si;
1604 #ifdef linux
1605     FILE *f;
1606 #endif
1607 #if defined(__FreeBSD__) || defined(__NetBSD__)
1608     int *tmp;
1609     int size_sys;
1610     int mib[2] = { CTL_HW };
1611 #endif
1612     if (time(NULL)==cache_lastchecked) {
1613         memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS));
1614         return;
1615     }
1616     cache_lastchecked = time(NULL);
1617
1618     lpmem->dwMemoryLoad    = 0;
1619     lpmem->dwTotalPhys     = 16*1024*1024;
1620     lpmem->dwAvailPhys     = 16*1024*1024;
1621     lpmem->dwTotalPageFile = 16*1024*1024;
1622     lpmem->dwAvailPageFile = 16*1024*1024;
1623
1624 #ifdef linux
1625     f = fopen( "/proc/meminfo", "r" );
1626     if (f)
1627     {
1628         char buffer[256];
1629         int total, used, free, shared, buffers, cached;
1630
1631         lpmem->dwLength = sizeof(MEMORYSTATUS);
1632         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1633         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1634         while (fgets( buffer, sizeof(buffer), f ))
1635         {
1636             /* old style /proc/meminfo ... */
1637             if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
1638             {
1639                 lpmem->dwTotalPhys += total;
1640                 lpmem->dwAvailPhys += free + buffers + cached;
1641             }
1642             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1643             {
1644                 lpmem->dwTotalPageFile += total;
1645                 lpmem->dwAvailPageFile += free;
1646             }
1647
1648             /* new style /proc/meminfo ... */
1649             if (sscanf(buffer, "MemTotal: %d", &total))
1650                 lpmem->dwTotalPhys = total*1024;
1651             if (sscanf(buffer, "MemFree: %d", &free))
1652                 lpmem->dwAvailPhys = free*1024;
1653             if (sscanf(buffer, "SwapTotal: %d", &total))
1654                 lpmem->dwTotalPageFile = total*1024;
1655             if (sscanf(buffer, "SwapFree: %d", &free))
1656                 lpmem->dwAvailPageFile = free*1024;
1657             if (sscanf(buffer, "Buffers: %d", &buffers))
1658                 lpmem->dwAvailPhys += buffers*1024;
1659             if (sscanf(buffer, "Cached: %d", &cached))
1660                 lpmem->dwAvailPhys += cached*1024;
1661         }
1662         fclose( f );
1663
1664         if (lpmem->dwTotalPhys)
1665         {
1666             DWORD TotalPhysical = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1667             DWORD AvailPhysical = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1668             lpmem->dwMemoryLoad = (TotalPhysical-AvailPhysical)
1669                                       / (TotalPhysical / 100);
1670         }
1671     }
1672 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1673     mib[1] = HW_PHYSMEM;
1674     sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1675     tmp = malloc(size_sys * sizeof(int));
1676     sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1677     if (tmp && *tmp)
1678     {
1679         lpmem->dwTotalPhys = *tmp;
1680         free(tmp);
1681         mib[1] = HW_USERMEM;
1682         sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1683         tmp = malloc(size_sys * sizeof(int));
1684         sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1685         if (tmp && *tmp)
1686         {
1687             lpmem->dwAvailPhys = *tmp;
1688             lpmem->dwTotalPageFile = *tmp;
1689             lpmem->dwAvailPageFile = *tmp;
1690             lpmem->dwMemoryLoad = lpmem->dwTotalPhys - lpmem->dwAvailPhys;
1691         } else
1692         {
1693             lpmem->dwAvailPhys = lpmem->dwTotalPhys;
1694             lpmem->dwTotalPageFile = lpmem->dwTotalPhys;
1695             lpmem->dwAvailPageFile = lpmem->dwTotalPhys;
1696             lpmem->dwMemoryLoad = 0;
1697         }
1698         free(tmp);
1699
1700     }
1701 #endif
1702     /* Some applications (e.g. QuickTime 6) crash if we tell them there
1703      * is more than 2GB of physical memory.
1704      */
1705     if (lpmem->dwTotalPhys>2U*1024*1024*1024)
1706     {
1707         lpmem->dwTotalPhys=2U*1024*1024*1024;
1708         lpmem->dwAvailPhys=2U*1024*1024*1024;
1709     }
1710
1711     /* FIXME: should do something for other systems */
1712     GetSystemInfo(&si);
1713     lpmem->dwTotalVirtual  = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
1714     /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
1715     lpmem->dwAvailVirtual  = lpmem->dwTotalVirtual-64*1024;
1716     memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS));
1717
1718     /* it appears some memory display programs want to divide by these values */
1719     if(lpmem->dwTotalPageFile==0)
1720         lpmem->dwTotalPageFile++;
1721
1722     if(lpmem->dwAvailPageFile==0)
1723         lpmem->dwAvailPageFile++;
1724
1725     TRACE("<-- LPMEMORYSTATUS: dwLength %ld, dwMemoryLoad %ld, dwTotalPhys %ld, dwAvailPhys %ld,"
1726           " dwTotalPageFile %ld, dwAvailPageFile %ld, dwTotalVirtual %ld, dwAvailVirtual %ld\n",
1727           lpmem->dwLength, lpmem->dwMemoryLoad, lpmem->dwTotalPhys, lpmem->dwAvailPhys,
1728           lpmem->dwTotalPageFile, lpmem->dwAvailPageFile, lpmem->dwTotalVirtual,
1729           lpmem->dwAvailVirtual);
1730 }
1731
1732 /***********************************************************************
1733  *           GlobalMemoryStatusEx   (KERNEL32.@)
1734  * A version of GlobalMemoryStatus that can deal with memory over 4GB
1735  *
1736  * RETURNS
1737  *      None
1738  */
1739 BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer ) {
1740   MEMORYSTATUS memstatus;
1741   
1742   /* Because GlobalMemoryStatusEx is identical to GlobalMemoryStatus save
1743      for one extra field in the struct, and the lack of a bug, we simply
1744      call GlobalMemoryStatus and copy the values across. */
1745   FIXME("we should emulate the 4GB bug here, as per MSDN\n");
1746   GlobalMemoryStatus(&memstatus);
1747   lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
1748   lpBuffer->ullTotalPhys = memstatus.dwTotalPhys;
1749   lpBuffer->ullAvailPhys = memstatus.dwAvailPhys;
1750   lpBuffer->ullTotalPageFile = memstatus.dwTotalPageFile;
1751   lpBuffer->ullAvailPageFile = memstatus.dwAvailPageFile;
1752   lpBuffer->ullTotalVirtual = memstatus.dwTotalVirtual;
1753   lpBuffer->ullAvailVirtual = memstatus.dwAvailVirtual;
1754   /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
1755      memory in the extended portion of the virtual address space of the calling
1756      process, in bytes.
1757      
1758      However, I don't know what this means, so set it to zero :(
1759   */
1760   lpBuffer->ullAvailExtendedVirtual = 0;
1761   return 1;
1762 }
1763
1764 /***********************************************************************
1765  *           A20Proc   (KERNEL.165)
1766  *           A20_Proc  (SYSTEM.20)
1767  */
1768 void WINAPI A20Proc16( WORD unused )
1769 {
1770     /* this is also a NOP in Windows */
1771 }
1772
1773 /***********************************************************************
1774  *           LimitEMSPages   (KERNEL.156)
1775  */
1776 DWORD WINAPI LimitEMSPages16( DWORD unused )
1777 {
1778     return 0;
1779 }