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