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