Worked around some tooltips hide problems by checking the current tooltip.
[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(0)) &&
316         ((char *)ptr <= DOSMEM_MemoryBase(0) + 0x100000))
317         ptr = DOSMEM_ResizeBlock(0, 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( 0, 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( 0, 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(size)
1043       {
1044          palloc=HeapAlloc(heap, hpflags, size+sizeof(HGLOBAL));
1045          *(HGLOBAL *)palloc=INTERN_TO_HANDLE(pintern);
1046          pintern->Pointer=(char *) palloc+sizeof(HGLOBAL);
1047       }
1048       else
1049          pintern->Pointer=NULL;
1050       pintern->Magic=MAGIC_GLOBAL_USED;
1051       pintern->Flags=flags>>8;
1052       pintern->LockCount=0;
1053       
1054       /* HeapUnlock(heap); */
1055        
1056       return INTERN_TO_HANDLE(pintern);
1057    }
1058 }
1059
1060
1061 /***********************************************************************
1062  *           GlobalLock   (KERNEL32.326)
1063  * RETURNS
1064  *      Pointer to first byte of block
1065  *      NULL: Failure
1066  */
1067 LPVOID WINAPI GlobalLock(
1068               HGLOBAL hmem /* [in] Handle of global memory object */
1069 ) {
1070    PGLOBAL32_INTERN pintern;
1071    LPVOID           palloc;
1072
1073    if(ISPOINTER(hmem))
1074       return (LPVOID) hmem;
1075
1076    /* HeapLock(GetProcessHeap()); */
1077    
1078    pintern=HANDLE_TO_INTERN(hmem);
1079    if(pintern->Magic==MAGIC_GLOBAL_USED)
1080    {
1081       if(pintern->LockCount<GLOBAL_LOCK_MAX)
1082          pintern->LockCount++;
1083       palloc=pintern->Pointer;
1084    }
1085    else
1086    {
1087       WARN("invalid handle\n");
1088       palloc=(LPVOID) NULL;
1089    }
1090    /* HeapUnlock(GetProcessHeap()); */;
1091    return palloc;
1092 }
1093
1094
1095 /***********************************************************************
1096  *           GlobalUnlock   (KERNEL32.332)
1097  * RETURNS
1098  *      TRUE: Object is still locked
1099  *      FALSE: Object is unlocked
1100  */
1101 BOOL WINAPI GlobalUnlock(
1102               HGLOBAL hmem /* [in] Handle of global memory object */
1103 ) {
1104    PGLOBAL32_INTERN       pintern;
1105    BOOL                 locked;
1106
1107    if(ISPOINTER(hmem))
1108       return FALSE;
1109
1110    /* HeapLock(GetProcessHeap()); */
1111    pintern=HANDLE_TO_INTERN(hmem);
1112    
1113    if(pintern->Magic==MAGIC_GLOBAL_USED)
1114    {
1115       if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
1116          pintern->LockCount--;
1117
1118       locked=(pintern->LockCount==0) ? FALSE : TRUE;
1119    }
1120    else
1121    {
1122       WARN("invalid handle\n");
1123       locked=FALSE;
1124    }
1125    /* HeapUnlock(GetProcessHeap()); */
1126    return locked;
1127 }
1128
1129
1130 /***********************************************************************
1131  *           GlobalHandle   (KERNEL32.325)
1132  * Returns the handle associated with the specified pointer.
1133  *
1134  * NOTES
1135  *      Since there in only one goto, can it be removed and the return
1136  *      be put 'inline'?
1137  *
1138  * RETURNS
1139  *      Handle: Success
1140  *      NULL: Failure
1141  */
1142 HGLOBAL WINAPI GlobalHandle(
1143                  LPCVOID pmem /* [in] Pointer to global memory block */
1144 ) {
1145     HGLOBAL handle;
1146     HANDLE heap;
1147     PGLOBAL32_INTERN  maybe_intern;
1148     LPCVOID test;
1149
1150     if (!pmem)
1151     {
1152        SetLastError( ERROR_INVALID_PARAMETER );
1153        return 0;
1154     }
1155
1156 /* note that if pmem is a pointer to a a block allocated by        */
1157 /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate  */
1158 /* will fail.                                                      */
1159     if (ISPOINTER(pmem)) {
1160         heap = GLOBAL_GetHeap( (HGLOBAL)pmem );
1161         if (HeapValidate( heap, 0, pmem ))
1162             return (HGLOBAL)pmem;  /* valid fixed block */
1163     handle = POINTER_TO_HANDLE(pmem);
1164     } else  
1165         handle = (HGLOBAL)pmem;
1166
1167 /* Now test handle either passed in or retrieved from pointer */
1168     heap = GLOBAL_GetHeap( handle );
1169     maybe_intern = HANDLE_TO_INTERN( handle );
1170     if (maybe_intern->Magic == MAGIC_GLOBAL_USED) {
1171         test = maybe_intern->Pointer;
1172         if (HeapValidate( heap, 0, ((HGLOBAL *)test)-1 ) &&
1173                                               /* obj(-handle) valid arena? */
1174             HeapValidate( heap, 0, maybe_intern ))  /* intern valid arena? */
1175             return handle;  /* valid moveable block */
1176     }
1177
1178     SetLastError( ERROR_INVALID_HANDLE );
1179     return 0;
1180 }
1181
1182
1183 /***********************************************************************
1184  *           GlobalReAlloc   (KERNEL32.328)
1185  * RETURNS
1186  *      Handle: Success
1187  *      NULL: Failure
1188  */
1189 HGLOBAL WINAPI GlobalReAlloc(
1190                  HGLOBAL hmem, /* [in] Handle of global memory object */
1191                  DWORD size,     /* [in] New size of block */
1192                  UINT flags    /* [in] How to reallocate object */
1193 ) {
1194    LPVOID               palloc;
1195    HGLOBAL            hnew;
1196    PGLOBAL32_INTERN     pintern;
1197    HANDLE heap = GLOBAL_GetHeap( hmem );
1198    DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
1199
1200    hnew = 0;
1201    /* HeapLock(heap); */
1202    if(flags & GMEM_MODIFY) /* modify flags */
1203    {
1204       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
1205       {
1206          /* make a fixed block moveable
1207           * actually only NT is able to do this. But it's soo simple
1208           */
1209          if (hmem == 0)
1210          {
1211              ERR("GlobalReAlloc32 with null handle!\n");
1212              SetLastError( ERROR_NOACCESS );
1213              return 0;
1214          }
1215          size=HeapSize(heap, 0, (LPVOID) hmem);
1216          hnew=GlobalAlloc( flags, size);
1217          palloc=GlobalLock(hnew);
1218          memcpy(palloc, (LPVOID) hmem, size);
1219          GlobalUnlock(hnew);
1220          GlobalFree(hmem);
1221       }
1222       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
1223       {
1224          /* change the flags to make our block "discardable" */
1225          pintern=HANDLE_TO_INTERN(hmem);
1226          pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
1227          hnew=hmem;
1228       }
1229       else
1230       {
1231          SetLastError(ERROR_INVALID_PARAMETER);
1232          hnew = 0;
1233       }
1234    }
1235    else
1236    {
1237       if(ISPOINTER(hmem))
1238       {
1239          /* reallocate fixed memory */
1240          hnew=(HGLOBAL)HeapReAlloc(heap, heap_flags, (LPVOID) hmem, size);
1241       }
1242       else
1243       {
1244          /* reallocate a moveable block */
1245          pintern=HANDLE_TO_INTERN(hmem);
1246          if(pintern->LockCount>1) {
1247             ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
1248             SetLastError(ERROR_INVALID_HANDLE);
1249          } else if(size!=0)
1250          {
1251             hnew=hmem;
1252             if(pintern->Pointer)
1253             {
1254                if((palloc = HeapReAlloc(heap, heap_flags,
1255                                    (char *) pintern->Pointer-sizeof(HGLOBAL),
1256                                    size+sizeof(HGLOBAL))) == NULL)
1257                    return 0; /* Block still valid */
1258                pintern->Pointer=(char *) palloc+sizeof(HGLOBAL);
1259             }
1260             else
1261             {
1262                 if((palloc=HeapAlloc(heap, heap_flags, size+sizeof(HGLOBAL)))
1263                    == NULL)
1264                     return 0;
1265                *(HGLOBAL *)palloc=hmem;
1266                pintern->Pointer=(char *) palloc+sizeof(HGLOBAL);
1267             }
1268          }
1269          else
1270          {
1271             if(pintern->Pointer)
1272             {
1273                HeapFree(heap, 0, (char *) pintern->Pointer-sizeof(HGLOBAL));
1274                pintern->Pointer=NULL;
1275             }
1276          }
1277       }
1278    }
1279    /* HeapUnlock(heap); */
1280    return hnew;
1281 }
1282
1283
1284 /***********************************************************************
1285  *           GlobalFree   (KERNEL32.322)
1286  * RETURNS
1287  *      NULL: Success
1288  *      Handle: Failure
1289  */
1290 HGLOBAL WINAPI GlobalFree(
1291                  HGLOBAL hmem /* [in] Handle of global memory object */
1292 ) {
1293    PGLOBAL32_INTERN pintern;
1294    HGLOBAL        hreturned = 0;
1295    HANDLE heap = GLOBAL_GetHeap( hmem );
1296    
1297    if(ISPOINTER(hmem)) /* POINTER */
1298    {
1299       if(!HeapFree(heap, 0, (LPVOID) hmem)) hmem = 0;
1300    }
1301    else  /* HANDLE */
1302    {
1303       /* HeapLock(heap); */
1304       pintern=HANDLE_TO_INTERN(hmem);
1305       
1306       if(pintern->Magic==MAGIC_GLOBAL_USED)
1307       {  
1308
1309 /* WIN98 does not make this test. That is you can free a */
1310 /* block you have not unlocked. Go figure!!              */
1311       /* if(pintern->LockCount!=0)  */
1312       /*    SetLastError(ERROR_INVALID_HANDLE);  */
1313
1314          if(pintern->Pointer)
1315             if(!HeapFree(heap, 0,
1316                          (char *)(pintern->Pointer)-sizeof(HGLOBAL)))
1317                hreturned=hmem;
1318          if(!HeapFree(heap, 0, pintern))
1319             hreturned=hmem;
1320       }      
1321       /* HeapUnlock(heap); */
1322    }
1323    return hreturned;
1324 }
1325
1326
1327 /***********************************************************************
1328  *           GlobalSize   (KERNEL32.329)
1329  * RETURNS
1330  *      Size in bytes of the global memory object
1331  *      0: Failure
1332  */
1333 DWORD WINAPI GlobalSize(
1334              HGLOBAL hmem /* [in] Handle of global memory object */
1335 ) {
1336    DWORD                retval;
1337    PGLOBAL32_INTERN     pintern;
1338    HANDLE heap          = GLOBAL_GetHeap( hmem );
1339
1340    if(ISPOINTER(hmem)) 
1341    {
1342       retval=HeapSize(heap, 0,  (LPVOID) hmem);
1343    }
1344    else
1345    {
1346       /* HeapLock(heap); */
1347       pintern=HANDLE_TO_INTERN(hmem);
1348       
1349       if(pintern->Magic==MAGIC_GLOBAL_USED)
1350       {
1351         if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */
1352             return 0;
1353          retval=HeapSize(heap, 0,
1354                          (char *)(pintern->Pointer)-sizeof(HGLOBAL))-4;
1355          if (retval == 0xffffffff-4) retval = 0;
1356       }
1357       else
1358       {
1359          WARN("invalid handle\n");
1360          retval=0;
1361       }
1362       /* HeapUnlock(heap); */
1363    }
1364    /* HeapSize returns 0xffffffff on failure */
1365    if (retval == 0xffffffff) retval = 0;
1366    return retval;
1367 }
1368
1369
1370 /***********************************************************************
1371  *           GlobalWire   (KERNEL32.333)
1372  */
1373 LPVOID WINAPI GlobalWire(HGLOBAL hmem)
1374 {
1375    return GlobalLock( hmem );
1376 }
1377
1378
1379 /***********************************************************************
1380  *           GlobalUnWire   (KERNEL32.330)
1381  */
1382 BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
1383 {
1384    return GlobalUnlock( hmem);
1385 }
1386
1387
1388 /***********************************************************************
1389  *           GlobalFix   (KERNEL32.320)
1390  */
1391 VOID WINAPI GlobalFix(HGLOBAL hmem)
1392 {
1393     GlobalLock( hmem );
1394 }
1395
1396
1397 /***********************************************************************
1398  *           GlobalUnfix   (KERNEL32.331)
1399  */
1400 VOID WINAPI GlobalUnfix(HGLOBAL hmem)
1401 {
1402    GlobalUnlock( hmem);
1403 }
1404
1405
1406 /***********************************************************************
1407  *           GlobalFlags   (KERNEL32.321)
1408  * Returns information about the specified global memory object
1409  *
1410  * NOTES
1411  *      Should this return GMEM_INVALID_HANDLE on invalid handle?
1412  *
1413  * RETURNS
1414  *      Value specifying allocation flags and lock count
1415  *      GMEM_INVALID_HANDLE: Failure
1416  */
1417 UINT WINAPI GlobalFlags(
1418               HGLOBAL hmem /* [in] Handle to global memory object */
1419 ) {
1420    DWORD                retval;
1421    PGLOBAL32_INTERN     pintern;
1422    
1423    if(ISPOINTER(hmem))
1424    {
1425       retval=0;
1426    }
1427    else
1428    {
1429       /* HeapLock(GetProcessHeap()); */
1430       pintern=HANDLE_TO_INTERN(hmem);
1431       if(pintern->Magic==MAGIC_GLOBAL_USED)
1432       {               
1433          retval=pintern->LockCount + (pintern->Flags<<8);
1434          if(pintern->Pointer==0)
1435             retval|= GMEM_DISCARDED;
1436       }
1437       else
1438       {
1439          WARN("Invalid handle: %04x", hmem);
1440          retval=0;
1441       }
1442       /* HeapUnlock(GetProcessHeap()); */
1443    }
1444    return retval;
1445 }
1446
1447
1448 /***********************************************************************
1449  *           GlobalCompact   (KERNEL32.316)
1450  */
1451 DWORD WINAPI GlobalCompact( DWORD minfree )
1452 {
1453     return 0;  /* GlobalCompact does nothing in Win32 */
1454 }
1455
1456
1457 /***********************************************************************
1458  *           GlobalMemoryStatus   (KERNEL32.327)
1459  * RETURNS
1460  *      None
1461  */
1462 VOID WINAPI GlobalMemoryStatus(
1463             LPMEMORYSTATUS lpmem
1464 ) {
1465     static MEMORYSTATUS cached_memstatus;
1466     static int cache_lastchecked = 0;
1467 #ifdef linux
1468     FILE *f;
1469 #endif
1470
1471     if (time(NULL)==cache_lastchecked) {
1472         memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS));
1473         return;
1474     }
1475     cache_lastchecked = time(NULL);
1476
1477 #ifdef linux
1478     f = fopen( "/proc/meminfo", "r" );
1479     if (f)
1480     {
1481         char buffer[256];
1482         int total, used, free, shared, buffers, cached;
1483
1484         lpmem->dwLength = sizeof(MEMORYSTATUS);
1485         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1486         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1487         while (fgets( buffer, sizeof(buffer), f ))
1488         {
1489             /* old style /proc/meminfo ... */
1490             if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
1491             {
1492                 lpmem->dwTotalPhys += total;
1493                 lpmem->dwAvailPhys += free + buffers + cached;
1494             }
1495             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1496             {
1497                 lpmem->dwTotalPageFile += total;
1498                 lpmem->dwAvailPageFile += free;
1499             }
1500
1501             /* new style /proc/meminfo ... */
1502             if (sscanf(buffer, "MemTotal: %d", &total))
1503                 lpmem->dwTotalPhys = total*1024;
1504             if (sscanf(buffer, "MemFree: %d", &free))
1505                 lpmem->dwAvailPhys = free*1024;
1506             if (sscanf(buffer, "SwapTotal: %d", &total))
1507                 lpmem->dwTotalPageFile = total*1024;
1508             if (sscanf(buffer, "SwapFree: %d", &free))
1509                 lpmem->dwAvailPageFile = free*1024;
1510             if (sscanf(buffer, "Buffers: %d", &buffers))
1511                 lpmem->dwAvailPhys += buffers*1024;
1512             if (sscanf(buffer, "Cached: %d", &cached))
1513                 lpmem->dwAvailPhys += cached*1024;
1514         }
1515         fclose( f );
1516
1517         if (lpmem->dwTotalPhys)
1518         {
1519             lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1520             lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1521             lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
1522                                       / (lpmem->dwTotalVirtual / 100);
1523         }
1524     } else
1525 #endif
1526     {
1527         /* FIXME: should do something for other systems */
1528         lpmem->dwMemoryLoad    = 0;
1529         lpmem->dwTotalPhys     = 16*1024*1024;
1530         lpmem->dwAvailPhys     = 16*1024*1024;
1531         lpmem->dwTotalPageFile = 16*1024*1024;
1532         lpmem->dwAvailPageFile = 16*1024*1024;
1533         lpmem->dwTotalVirtual  = 32*1024*1024;
1534         lpmem->dwAvailVirtual  = 32*1024*1024;
1535     }
1536     memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS));
1537 }
1538
1539 /***********************************************************************
1540  *           A20Proc16   (KERNEL.165)
1541  */
1542 void WINAPI A20Proc16( WORD unused )
1543 {
1544     /* this is also a NOP in Windows */
1545 }
1546
1547 /***********************************************************************
1548  *           LimitEMSPages16   (KERNEL.156)
1549  */
1550 DWORD WINAPI LimitEMSPages16( DWORD unused )
1551 {
1552     return 0;
1553 }