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