- GetScrollRange zeros the return parameters for no infoPtr
[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 then 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)          (((DWORD)(h)&2)!=0)
1062 #define ISPOINTER(h)         (((DWORD)(h)&2)==0)
1063 /* allign 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       /* HeapLock(heap); */
1108
1109       pintern=HeapAlloc(GetProcessHeap(), 0,  sizeof(GLOBAL32_INTERN));
1110       if (!pintern) return 0;
1111       if(size)
1112       {
1113          if (!(palloc=HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE))) {
1114             HeapFree(GetProcessHeap(), 0, pintern);
1115             return 0;
1116          }
1117          *(HGLOBAL *)palloc=INTERN_TO_HANDLE(pintern);
1118          pintern->Pointer=(char *) palloc+HGLOBAL_STORAGE;
1119       }
1120       else
1121          pintern->Pointer=NULL;
1122       pintern->Magic=MAGIC_GLOBAL_USED;
1123       pintern->Flags=flags>>8;
1124       pintern->LockCount=0;
1125
1126       /* HeapUnlock(heap); */
1127
1128       return INTERN_TO_HANDLE(pintern);
1129    }
1130 }
1131
1132
1133 /***********************************************************************
1134  *           GlobalLock   (KERNEL32.@)
1135  * RETURNS
1136  *      Pointer to first byte of block
1137  *      NULL: Failure
1138  */
1139 LPVOID WINAPI GlobalLock(
1140               HGLOBAL hmem /* [in] Handle of global memory object */
1141 ) {
1142    PGLOBAL32_INTERN pintern;
1143    LPVOID           palloc;
1144
1145    if(ISPOINTER(hmem))
1146       return (LPVOID) hmem;
1147
1148    /* HeapLock(GetProcessHeap()); */
1149
1150    pintern=HANDLE_TO_INTERN(hmem);
1151    if(pintern->Magic==MAGIC_GLOBAL_USED)
1152    {
1153       if(pintern->LockCount<GLOBAL_LOCK_MAX)
1154          pintern->LockCount++;
1155       palloc=pintern->Pointer;
1156    }
1157    else
1158    {
1159       WARN("invalid handle\n");
1160       palloc=NULL;
1161       SetLastError(ERROR_INVALID_HANDLE);
1162    }
1163    /* HeapUnlock(GetProcessHeap()); */;
1164    return palloc;
1165 }
1166
1167
1168 /***********************************************************************
1169  *           GlobalUnlock   (KERNEL32.@)
1170  * RETURNS
1171  *      TRUE: Object is still locked
1172  *      FALSE: Object is unlocked
1173  */
1174 BOOL WINAPI GlobalUnlock(
1175               HGLOBAL hmem /* [in] Handle of global memory object */
1176 ) {
1177     PGLOBAL32_INTERN pintern;
1178     BOOL locked;
1179
1180     if (ISPOINTER(hmem)) return FALSE;
1181
1182     __TRY
1183     {
1184         /* HeapLock(GetProcessHeap()); */
1185         pintern=HANDLE_TO_INTERN(hmem);
1186         if(pintern->Magic==MAGIC_GLOBAL_USED)
1187         {
1188             if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
1189                 pintern->LockCount--;
1190
1191             locked = (pintern->LockCount != 0);
1192             if (!locked) SetLastError(NO_ERROR);
1193         }
1194         else
1195         {
1196             WARN("invalid handle\n");
1197             SetLastError(ERROR_INVALID_HANDLE);
1198             locked=FALSE;
1199         }
1200         /* HeapUnlock(GetProcessHeap()); */
1201     }
1202     __EXCEPT(page_fault)
1203     {
1204         ERR("page fault occurred ! Caused by bug ?\n");
1205         SetLastError( ERROR_INVALID_PARAMETER );
1206         return FALSE;
1207     }
1208     __ENDTRY
1209     return locked;
1210 }
1211
1212
1213 /***********************************************************************
1214  *           GlobalHandle   (KERNEL32.@)
1215  * Returns the handle associated with the specified pointer.
1216  *
1217  * RETURNS
1218  *      Handle: Success
1219  *      NULL: Failure
1220  */
1221 HGLOBAL WINAPI GlobalHandle(
1222                  LPCVOID pmem /* [in] Pointer to global memory block */
1223 ) {
1224     HGLOBAL handle;
1225     PGLOBAL32_INTERN  maybe_intern;
1226     LPCVOID test;
1227
1228     if (!pmem)
1229     {
1230         SetLastError( ERROR_INVALID_PARAMETER );
1231         return 0;
1232     }
1233
1234     __TRY
1235     {
1236         handle = 0;
1237
1238         /* note that if pmem is a pointer to a a block allocated by        */
1239         /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate  */
1240         /* will fail.                                                      */
1241         if (ISPOINTER(pmem)) {
1242             if (HeapValidate( GetProcessHeap(), 0, pmem )) {
1243                 handle = (HGLOBAL)pmem;  /* valid fixed block */
1244                 break;
1245             }
1246             handle = POINTER_TO_HANDLE(pmem);
1247         } else
1248             handle = (HGLOBAL)pmem;
1249
1250         /* Now test handle either passed in or retrieved from pointer */
1251         maybe_intern = HANDLE_TO_INTERN( handle );
1252         if (maybe_intern->Magic == MAGIC_GLOBAL_USED) {
1253             test = maybe_intern->Pointer;
1254             if (HeapValidate( GetProcessHeap(), 0, (char *)test - HGLOBAL_STORAGE ) && /* obj(-handle) valid arena? */
1255                 HeapValidate( GetProcessHeap(), 0, maybe_intern ))  /* intern valid arena? */
1256                 break;  /* valid moveable block */
1257         }
1258         handle = 0;
1259         SetLastError( ERROR_INVALID_HANDLE );
1260     }
1261     __EXCEPT(page_fault)
1262     {
1263         SetLastError( ERROR_INVALID_HANDLE );
1264         return 0;
1265     }
1266     __ENDTRY
1267
1268     return handle;
1269 }
1270
1271
1272 /***********************************************************************
1273  *           GlobalReAlloc   (KERNEL32.@)
1274  * RETURNS
1275  *      Handle: Success
1276  *      NULL: Failure
1277  */
1278 HGLOBAL WINAPI GlobalReAlloc(
1279                  HGLOBAL hmem, /* [in] Handle of global memory object */
1280                  SIZE_T size,  /* [in] New size of block */
1281                  UINT flags    /* [in] How to reallocate object */
1282 ) {
1283    LPVOID               palloc;
1284    HGLOBAL            hnew;
1285    PGLOBAL32_INTERN     pintern;
1286    DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
1287
1288    hnew = 0;
1289    /* HeapLock(heap); */
1290    if(flags & GMEM_MODIFY) /* modify flags */
1291    {
1292       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
1293       {
1294          /* make a fixed block moveable
1295           * actually only NT is able to do this. But it's soo simple
1296           */
1297          if (hmem == 0)
1298          {
1299              ERR("GlobalReAlloc32 with null handle!\n");
1300              SetLastError( ERROR_NOACCESS );
1301              return 0;
1302          }
1303          size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
1304          hnew=GlobalAlloc( flags, size);
1305          palloc=GlobalLock(hnew);
1306          memcpy(palloc, (LPVOID) hmem, size);
1307          GlobalUnlock(hnew);
1308          GlobalFree(hmem);
1309       }
1310       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
1311       {
1312          /* change the flags to make our block "discardable" */
1313          pintern=HANDLE_TO_INTERN(hmem);
1314          pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
1315          hnew=hmem;
1316       }
1317       else
1318       {
1319          SetLastError(ERROR_INVALID_PARAMETER);
1320          hnew = 0;
1321       }
1322    }
1323    else
1324    {
1325       if(ISPOINTER(hmem))
1326       {
1327          /* reallocate fixed memory */
1328          hnew=(HGLOBAL)HeapReAlloc(GetProcessHeap(), heap_flags, (LPVOID) hmem, size);
1329       }
1330       else
1331       {
1332          /* reallocate a moveable block */
1333          pintern=HANDLE_TO_INTERN(hmem);
1334
1335 #if 0
1336 /* Apparently Windows doesn't care whether the handle is locked at this point */
1337 /* See also the same comment in GlobalFree() */
1338          if(pintern->LockCount>1) {
1339             ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
1340             SetLastError(ERROR_INVALID_HANDLE);
1341          } else
1342 #endif
1343          if(size!=0)
1344          {
1345             hnew=hmem;
1346             if(pintern->Pointer)
1347             {
1348                if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags,
1349                                    (char *) pintern->Pointer-HGLOBAL_STORAGE,
1350                                    size+HGLOBAL_STORAGE)) == NULL)
1351                    return 0; /* Block still valid */
1352                pintern->Pointer=(char *) palloc+HGLOBAL_STORAGE;
1353             }
1354             else
1355             {
1356                 if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE))
1357                    == NULL)
1358                     return 0;
1359                *(HGLOBAL *)palloc=hmem;
1360                pintern->Pointer=(char *) palloc+HGLOBAL_STORAGE;
1361             }
1362          }
1363          else
1364          {
1365             if(pintern->Pointer)
1366             {
1367                HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE);
1368                pintern->Pointer=NULL;
1369             }
1370          }
1371       }
1372    }
1373    /* HeapUnlock(heap); */
1374    return hnew;
1375 }
1376
1377
1378 /***********************************************************************
1379  *           GlobalFree   (KERNEL32.@)
1380  * RETURNS
1381  *      NULL: Success
1382  *      Handle: Failure
1383  */
1384 HGLOBAL WINAPI GlobalFree(
1385                  HGLOBAL hmem /* [in] Handle of global memory object */
1386 ) {
1387     PGLOBAL32_INTERN pintern;
1388     HGLOBAL hreturned;
1389
1390     __TRY
1391     {
1392         hreturned = 0;
1393         if(ISPOINTER(hmem)) /* POINTER */
1394         {
1395             if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
1396         }
1397         else  /* HANDLE */
1398         {
1399             /* HeapLock(heap); */
1400             pintern=HANDLE_TO_INTERN(hmem);
1401
1402             if(pintern->Magic==MAGIC_GLOBAL_USED)
1403             {
1404
1405                 /* WIN98 does not make this test. That is you can free a */
1406                 /* block you have not unlocked. Go figure!!              */
1407                 /* if(pintern->LockCount!=0)  */
1408                 /*    SetLastError(ERROR_INVALID_HANDLE);  */
1409
1410                 if(pintern->Pointer)
1411                     if(!HeapFree(GetProcessHeap(), 0, (char *)(pintern->Pointer)-HGLOBAL_STORAGE))
1412                         hreturned=hmem;
1413                 if(!HeapFree(GetProcessHeap(), 0, pintern))
1414                     hreturned=hmem;
1415             }
1416             /* HeapUnlock(heap); */
1417         }
1418     }
1419     __EXCEPT(page_fault)
1420     {
1421         ERR("page fault occurred ! Caused by bug ?\n");
1422         SetLastError( ERROR_INVALID_PARAMETER );
1423         return hmem;
1424     }
1425     __ENDTRY
1426     return hreturned;
1427 }
1428
1429
1430 /***********************************************************************
1431  *           GlobalSize   (KERNEL32.@)
1432  * RETURNS
1433  *      Size in bytes of the global memory object
1434  *      0: Failure
1435  */
1436 SIZE_T WINAPI GlobalSize(
1437              HGLOBAL hmem /* [in] Handle of global memory object */
1438 ) {
1439    DWORD                retval;
1440    PGLOBAL32_INTERN     pintern;
1441
1442    if(ISPOINTER(hmem))
1443    {
1444       retval=HeapSize(GetProcessHeap(), 0,  (LPVOID) hmem);
1445    }
1446    else
1447    {
1448       /* HeapLock(heap); */
1449       pintern=HANDLE_TO_INTERN(hmem);
1450
1451       if(pintern->Magic==MAGIC_GLOBAL_USED)
1452       {
1453         if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */
1454             return 0;
1455          retval=HeapSize(GetProcessHeap(), 0,
1456                          (char *)(pintern->Pointer) - HGLOBAL_STORAGE );
1457          if (retval != (DWORD)-1) retval -= HGLOBAL_STORAGE;
1458       }
1459       else
1460       {
1461          WARN("invalid handle\n");
1462          retval=0;
1463       }
1464       /* HeapUnlock(heap); */
1465    }
1466    /* HeapSize returns 0xffffffff on failure */
1467    if (retval == 0xffffffff) retval = 0;
1468    return retval;
1469 }
1470
1471
1472 /***********************************************************************
1473  *           GlobalWire   (KERNEL32.@)
1474  */
1475 LPVOID WINAPI GlobalWire(HGLOBAL hmem)
1476 {
1477    return GlobalLock( hmem );
1478 }
1479
1480
1481 /***********************************************************************
1482  *           GlobalUnWire   (KERNEL32.@)
1483  */
1484 BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
1485 {
1486    return GlobalUnlock( hmem);
1487 }
1488
1489
1490 /***********************************************************************
1491  *           GlobalFix   (KERNEL32.@)
1492  */
1493 VOID WINAPI GlobalFix(HGLOBAL hmem)
1494 {
1495     GlobalLock( hmem );
1496 }
1497
1498
1499 /***********************************************************************
1500  *           GlobalUnfix   (KERNEL32.@)
1501  */
1502 VOID WINAPI GlobalUnfix(HGLOBAL hmem)
1503 {
1504    GlobalUnlock( hmem);
1505 }
1506
1507
1508 /***********************************************************************
1509  *           GlobalFlags   (KERNEL32.@)
1510  * Returns information about the specified global memory object
1511  *
1512  * NOTES
1513  *      Should this return GMEM_INVALID_HANDLE on invalid handle?
1514  *
1515  * RETURNS
1516  *      Value specifying allocation flags and lock count
1517  *      GMEM_INVALID_HANDLE: Failure
1518  */
1519 UINT WINAPI GlobalFlags(
1520               HGLOBAL hmem /* [in] Handle to global memory object */
1521 ) {
1522    DWORD                retval;
1523    PGLOBAL32_INTERN     pintern;
1524
1525    if(ISPOINTER(hmem))
1526    {
1527       retval=0;
1528    }
1529    else
1530    {
1531       /* HeapLock(GetProcessHeap()); */
1532       pintern=HANDLE_TO_INTERN(hmem);
1533       if(pintern->Magic==MAGIC_GLOBAL_USED)
1534       {
1535          retval=pintern->LockCount + (pintern->Flags<<8);
1536          if(pintern->Pointer==0)
1537             retval|= GMEM_DISCARDED;
1538       }
1539       else
1540       {
1541          WARN("Invalid handle: %p\n", hmem);
1542          retval=0;
1543       }
1544       /* HeapUnlock(GetProcessHeap()); */
1545    }
1546    return retval;
1547 }
1548
1549
1550 /***********************************************************************
1551  *           GlobalCompact   (KERNEL32.@)
1552  */
1553 SIZE_T WINAPI GlobalCompact( DWORD minfree )
1554 {
1555     return 0;  /* GlobalCompact does nothing in Win32 */
1556 }
1557
1558
1559 /***********************************************************************
1560  *           GlobalMemoryStatus   (KERNEL32.@)
1561  * Provides information about the status of the memory, so apps can tell
1562  * roughly how much they are able to allocate
1563  * 
1564  * RETURNS
1565  *      None
1566  */
1567 VOID WINAPI GlobalMemoryStatus(
1568             LPMEMORYSTATUS lpmem
1569 ) {
1570     static MEMORYSTATUS cached_memstatus;
1571     static int cache_lastchecked = 0;
1572     SYSTEM_INFO si;
1573 #ifdef linux
1574     FILE *f;
1575 #endif
1576 #ifdef __FreeBSD__
1577     int *tmp;
1578     int size_sys;
1579 #endif
1580     if (time(NULL)==cache_lastchecked) {
1581         memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS));
1582         return;
1583     }
1584     cache_lastchecked = time(NULL);
1585
1586     lpmem->dwMemoryLoad    = 0;
1587     lpmem->dwTotalPhys     = 16*1024*1024;
1588     lpmem->dwAvailPhys     = 16*1024*1024;
1589     lpmem->dwTotalPageFile = 16*1024*1024;
1590     lpmem->dwAvailPageFile = 16*1024*1024;
1591
1592 #ifdef linux
1593     f = fopen( "/proc/meminfo", "r" );
1594     if (f)
1595     {
1596         char buffer[256];
1597         int total, used, free, shared, buffers, cached;
1598
1599         lpmem->dwLength = sizeof(MEMORYSTATUS);
1600         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1601         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1602         while (fgets( buffer, sizeof(buffer), f ))
1603         {
1604             /* old style /proc/meminfo ... */
1605             if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
1606             {
1607                 lpmem->dwTotalPhys += total;
1608                 lpmem->dwAvailPhys += free + buffers + cached;
1609             }
1610             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1611             {
1612                 lpmem->dwTotalPageFile += total;
1613                 lpmem->dwAvailPageFile += free;
1614             }
1615
1616             /* new style /proc/meminfo ... */
1617             if (sscanf(buffer, "MemTotal: %d", &total))
1618                 lpmem->dwTotalPhys = total*1024;
1619             if (sscanf(buffer, "MemFree: %d", &free))
1620                 lpmem->dwAvailPhys = free*1024;
1621             if (sscanf(buffer, "SwapTotal: %d", &total))
1622                 lpmem->dwTotalPageFile = total*1024;
1623             if (sscanf(buffer, "SwapFree: %d", &free))
1624                 lpmem->dwAvailPageFile = free*1024;
1625             if (sscanf(buffer, "Buffers: %d", &buffers))
1626                 lpmem->dwAvailPhys += buffers*1024;
1627             if (sscanf(buffer, "Cached: %d", &cached))
1628                 lpmem->dwAvailPhys += cached*1024;
1629         }
1630         fclose( f );
1631
1632         if (lpmem->dwTotalPhys)
1633         {
1634             DWORD TotalPhysical = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1635             DWORD AvailPhysical = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1636             lpmem->dwMemoryLoad = (TotalPhysical-AvailPhysical)
1637                                       / (TotalPhysical / 100);
1638         }
1639     }
1640 #elif defined(__FreeBSD__)
1641     sysctlbyname("hw.physmem", NULL, &size_sys, NULL, 0);
1642     tmp = malloc(size_sys * sizeof(int));
1643     sysctlbyname("hw.physmem", tmp, &size_sys, NULL, 0);
1644     if (tmp && *tmp)
1645     {
1646         lpmem->dwTotalPhys = *tmp;
1647         free(tmp);
1648         sysctlbyname("hw.usermem", NULL, &size_sys, NULL, 0);
1649         tmp = malloc(size_sys * sizeof(int));
1650         sysctlbyname("hw.usermem", tmp, &size_sys, NULL, 0);
1651         if (tmp && *tmp)
1652         {
1653             lpmem->dwAvailPhys = *tmp;
1654             lpmem->dwTotalPageFile = *tmp;
1655             lpmem->dwAvailPageFile = *tmp;
1656             lpmem->dwMemoryLoad = lpmem->dwTotalPhys - lpmem->dwAvailPhys;
1657         } else
1658         {
1659             lpmem->dwAvailPhys = lpmem->dwTotalPhys;
1660             lpmem->dwTotalPageFile = lpmem->dwTotalPhys;
1661             lpmem->dwAvailPageFile = lpmem->dwTotalPhys;
1662             lpmem->dwMemoryLoad = 0;
1663         }
1664         free(tmp);
1665
1666     }
1667 #endif
1668     /* Some applications (e.g. QuickTime 6) crash if we tell them there
1669      * is more than 2GB of physical memory.
1670      */
1671     if (lpmem->dwTotalPhys>2U*1024*1024*1024)
1672     {
1673         lpmem->dwTotalPhys=2U*1024*1024*1024;
1674         lpmem->dwAvailPhys=2U*1024*1024*1024;
1675     }
1676
1677     /* FIXME: should do something for other systems */
1678     GetSystemInfo(&si);
1679     lpmem->dwTotalVirtual  = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
1680     /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
1681     lpmem->dwAvailVirtual  = lpmem->dwTotalVirtual-64*1024;
1682     memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS));
1683
1684     /* it appears some memory display programs want to divide by these values */
1685     if(lpmem->dwTotalPageFile==0)
1686         lpmem->dwTotalPageFile++;
1687
1688     if(lpmem->dwAvailPageFile==0)
1689         lpmem->dwAvailPageFile++;
1690
1691     TRACE("<-- LPMEMORYSTATUS: dwLength %ld, dwMemoryLoad %ld, dwTotalPhys %ld, dwAvailPhys %ld,"
1692           " dwTotalPageFile %ld, dwAvailPageFile %ld, dwTotalVirtual %ld, dwAvailVirtual %ld\n",
1693           lpmem->dwLength, lpmem->dwMemoryLoad, lpmem->dwTotalPhys, lpmem->dwAvailPhys,
1694           lpmem->dwTotalPageFile, lpmem->dwAvailPageFile, lpmem->dwTotalVirtual,
1695           lpmem->dwAvailVirtual);
1696 }
1697
1698 /***********************************************************************
1699  *           GlobalMemoryStatusEx   (KERNEL32.@)
1700  * A version of GlobalMemoryStatus that can deal with memory over 4GB
1701  *
1702  * RETURNS
1703  *      None
1704  */
1705 BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer ) {
1706   MEMORYSTATUS memstatus;
1707   
1708   /* Because GlobalMemoryStatusEx is identical to GlobalMemoryStatus save
1709      for one extra field in the struct, and the lack of a bug, we simply
1710      call GlobalMemoryStatus and copy the values across. */
1711   FIXME("we should emulate the 4GB bug here, as per MSDN\n");
1712   GlobalMemoryStatus(&memstatus);
1713   lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
1714   lpBuffer->ullTotalPhys = memstatus.dwTotalPhys;
1715   lpBuffer->ullAvailPhys = memstatus.dwAvailPhys;
1716   lpBuffer->ullTotalPageFile = memstatus.dwTotalPageFile;
1717   lpBuffer->ullAvailPageFile = memstatus.dwAvailPageFile;
1718   lpBuffer->ullTotalVirtual = memstatus.dwTotalVirtual;
1719   lpBuffer->ullAvailVirtual = memstatus.dwAvailVirtual;
1720   /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
1721      memory in the extended portion of the virtual address space of the calling
1722      process, in bytes.
1723      
1724      However, I don't know what this means, so set it to zero :(
1725   */
1726   lpBuffer->ullAvailExtendedVirtual = 0;
1727   return 1;
1728 }
1729
1730 /***********************************************************************
1731  *           A20Proc   (KERNEL.165)
1732  *           A20_Proc  (SYSTEM.20)
1733  */
1734 void WINAPI A20Proc16( WORD unused )
1735 {
1736     /* this is also a NOP in Windows */
1737 }
1738
1739 /***********************************************************************
1740  *           LimitEMSPages   (KERNEL.156)
1741  */
1742 DWORD WINAPI LimitEMSPages16( DWORD unused )
1743 {
1744     return 0;
1745 }