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