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