wined3d: Map vertex sampler numbers to the correct internal array indices for GetText...
[wine] / dlls / kernel32 / global16.c
1 /*
2  * Global heap functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 /* 0xffff sometimes seems to mean: CURRENT_DS */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <string.h>
33 #ifdef HAVE_SYS_PARAM_H
34 #include <sys/param.h>
35 #endif
36 #ifdef HAVE_SYS_SYSCTL_H
37 #include <sys/sysctl.h>
38 #endif
39
40 #include "wine/winbase16.h"
41 #include "toolhelp.h"
42 #include "winternl.h"
43 #include "kernel_private.h"
44 #include "kernel16_private.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(global);
48
49   /* Global arena block */
50 typedef struct
51 {
52     void     *base;          /* Base address (0 if discarded) */
53     DWORD     size;          /* Size in bytes (0 indicates a free block) */
54     HGLOBAL16 handle;        /* Handle for this block */
55     HGLOBAL16 hOwner;        /* Owner of this block */
56     BYTE      lockCount;     /* Count of GlobalFix() calls */
57     BYTE      pageLockCount; /* Count of GlobalPageLock() calls */
58     BYTE      flags;         /* Allocation flags */
59     BYTE      selCount;      /* Number of selectors allocated for this block */
60 } GLOBALARENA;
61
62   /* Flags definitions */
63 #define GA_MOVEABLE     0x02  /* same as GMEM_MOVEABLE */
64 #define GA_DGROUP       0x04
65 #define GA_DISCARDABLE  0x08
66 #define GA_IPCSHARE     0x10  /* same as GMEM_DDESHARE */
67 #define GA_DOSMEM       0x20
68
69 /* Arena array (FIXME) */
70 static GLOBALARENA *pGlobalArena;
71 static int globalArenaSize;
72
73 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
74
75 #define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
76 #define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
77
78 static inline void*     DOSMEM_AllocBlock(UINT size, UINT16* pseg)
79 {
80     if (!winedos.AllocDosBlock) load_winedos();
81     return winedos.AllocDosBlock ? winedos.AllocDosBlock(size, pseg) : NULL;
82 }
83
84 static inline BOOL      DOSMEM_FreeBlock(void* ptr)
85 {
86     if (!winedos.FreeDosBlock) load_winedos();
87     return winedos.FreeDosBlock ? winedos.FreeDosBlock( ptr ) : FALSE;
88 }
89
90 static inline UINT      DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
91 {
92     if (!winedos.ResizeDosBlock) load_winedos();
93     return winedos.ResizeDosBlock ? winedos.ResizeDosBlock(ptr, size, TRUE) : 0;
94 }
95
96 /***********************************************************************
97  *           GLOBAL_GetArena
98  *
99  * Return the arena for a given selector, growing the arena array if needed.
100  */
101 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
102 {
103     if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
104     {
105         int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
106         GLOBALARENA *pNewArena = realloc( pGlobalArena,
107                                           newsize * sizeof(GLOBALARENA) );
108         if (!pNewArena) return 0;
109         pGlobalArena = pNewArena;
110         memset( pGlobalArena + globalArenaSize, 0,
111                 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
112         globalArenaSize = newsize;
113     }
114     return pGlobalArena + (sel >> __AHSHIFT);
115 }
116
117 void debug_handles(void)
118 {
119     int printed=0;
120     int i;
121     for (i = globalArenaSize-1 ; i>=0 ; i--) {
122         if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
123             printed=1;
124             DPRINTF("0x%08x, ",pGlobalArena[i].handle);
125         }
126     }
127     if (printed)
128         DPRINTF("\n");
129 }
130
131
132 /***********************************************************************
133  *           GLOBAL_CreateBlock
134  *
135  * Create a global heap block for a fixed range of linear memory.
136  */
137 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, void *ptr, DWORD size,
138                               HGLOBAL16 hOwner, unsigned char selflags )
139 {
140     WORD sel, selcount;
141     GLOBALARENA *pArena;
142
143       /* Allocate the selector(s) */
144
145     sel = SELECTOR_AllocBlock( ptr, size, selflags );
146     if (!sel) return 0;
147     selcount = (size + 0xffff) / 0x10000;
148
149     if (!(pArena = GLOBAL_GetArena( sel, selcount )))
150     {
151         SELECTOR_FreeBlock( sel );
152         return 0;
153     }
154
155       /* Fill the arena block */
156
157     pArena->base = ptr;
158     pArena->size = GetSelectorLimit16(sel) + 1;
159     pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
160     pArena->hOwner = hOwner;
161     pArena->lockCount = 0;
162     pArena->pageLockCount = 0;
163     pArena->flags = flags & GA_MOVEABLE;
164     if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
165     if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
166     if (!(selflags & (WINE_LDT_FLAGS_CODE^WINE_LDT_FLAGS_DATA))) pArena->flags |= GA_DGROUP;
167     pArena->selCount = selcount;
168     if (selcount > 1)  /* clear the next arena blocks */
169         memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
170
171     return pArena->handle;
172 }
173
174
175 /***********************************************************************
176  *           GLOBAL_FreeBlock
177  *
178  * Free a block allocated by GLOBAL_CreateBlock, without touching
179  * the associated linear memory range.
180  */
181 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
182 {
183     WORD sel;
184     GLOBALARENA *pArena;
185
186     if (!handle) return TRUE;
187     sel = GlobalHandleToSel16( handle );
188     if (!VALID_HANDLE(sel)) return FALSE;
189     pArena = GET_ARENA_PTR(sel);
190     SELECTOR_FreeBlock( sel );
191     memset( pArena, 0, sizeof(GLOBALARENA) );
192     return TRUE;
193 }
194
195 /***********************************************************************
196  *           GLOBAL_MoveBlock
197  */
198 BOOL16 GLOBAL_MoveBlock( HGLOBAL16 handle, void *ptr, DWORD size )
199 {
200     WORD sel;
201     GLOBALARENA *pArena;
202
203     if (!handle) return TRUE;
204     sel = GlobalHandleToSel16( handle );
205     if (!VALID_HANDLE(sel)) return FALSE;
206     pArena = GET_ARENA_PTR(sel);
207     if (pArena->selCount != 1)
208         return FALSE;
209
210     pArena->base = ptr;
211     pArena->size = size;
212     SELECTOR_ReallocBlock( sel, ptr, size );
213     return TRUE;
214 }
215
216 /***********************************************************************
217  *           GLOBAL_Alloc
218  *
219  * Implementation of GlobalAlloc16()
220  */
221 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner, unsigned char selflags )
222 {
223     void *ptr;
224     HGLOBAL16 handle;
225
226     TRACE("%d flags=%04x\n", size, flags );
227
228     /* If size is 0, create a discarded block */
229
230     if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, selflags );
231
232     /* Fixup the size */
233
234     if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
235     size = (size + 0x1f) & ~0x1f;
236
237     /* Allocate the linear memory */
238     ptr = HeapAlloc( GetProcessHeap(), 0, size );
239       /* FIXME: free discardable blocks and try again? */
240     if (!ptr) return 0;
241
242       /* Allocate the selector(s) */
243
244     handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner, selflags );
245     if (!handle)
246     {
247         HeapFree( GetProcessHeap(), 0, ptr );
248         return 0;
249     }
250
251     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
252     return handle;
253 }
254
255 /***********************************************************************
256  *           GlobalAlloc     (KERNEL.15)
257  *           GlobalAlloc16   (KERNEL32.24)
258  *
259  * Allocate a global memory object.
260  *
261  * RETURNS
262  *      Handle: Success
263  *      NULL: Failure
264  */
265 HGLOBAL16 WINAPI GlobalAlloc16(
266                  UINT16 flags, /* [in] Object allocation attributes */
267                  DWORD size    /* [in] Number of bytes to allocate */
268 ) {
269     HANDLE16 owner = GetCurrentPDB16();
270
271     if (flags & GMEM_DDESHARE)
272         owner = GetExePtr(owner);  /* Make it a module handle */
273     return GLOBAL_Alloc( flags, size, owner, WINE_LDT_FLAGS_DATA );
274 }
275
276
277 /***********************************************************************
278  *           GlobalReAlloc     (KERNEL.16)
279  *
280  * Change the size or attributes of a global memory object.
281  *
282  * RETURNS
283  *      Handle: Success
284  *      NULL: Failure
285  */
286 HGLOBAL16 WINAPI GlobalReAlloc16(
287                  HGLOBAL16 handle, /* [in] Handle of global memory object */
288                  DWORD size,       /* [in] New size of block */
289                  UINT16 flags      /* [in] How to reallocate object */
290 ) {
291     WORD selcount;
292     DWORD oldsize;
293     void *ptr, *newptr;
294     GLOBALARENA *pArena, *pNewArena;
295     WORD sel = GlobalHandleToSel16( handle );
296
297     TRACE("%04x %d flags=%04x\n",
298                     handle, size, flags );
299     if (!handle) return 0;
300
301     if (!VALID_HANDLE(handle))
302     {
303         WARN("Invalid handle 0x%04x!\n", handle);
304         return 0;
305     }
306     pArena = GET_ARENA_PTR( handle );
307
308       /* Discard the block if requested */
309
310     if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
311     {
312         if (!(pArena->flags & GA_MOVEABLE) ||
313             !(pArena->flags & GA_DISCARDABLE) ||
314             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
315         if (pArena->flags & GA_DOSMEM)
316             DOSMEM_FreeBlock( (void *)pArena->base );
317         else
318             HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
319         pArena->base = 0;
320
321         /* Note: we rely on the fact that SELECTOR_ReallocBlock won't
322          * change the selector if we are shrinking the block.
323          * FIXME: shouldn't we keep selectors until the block is deleted?
324          */
325         SELECTOR_ReallocBlock( sel, 0, 1 );
326         return handle;
327     }
328
329       /* Fixup the size */
330
331     if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
332     if (size == 0) size = 0x20;
333     else size = (size + 0x1f) & ~0x1f;
334
335       /* Change the flags */
336
337     if (flags & GMEM_MODIFY)
338     {
339           /* Change the flags, leaving GA_DGROUP alone */
340         pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
341         if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
342         return handle;
343     }
344
345       /* Reallocate the linear memory */
346
347     ptr = (void *)pArena->base;
348     oldsize = pArena->size;
349     TRACE("oldbase %p oldsize %08x newsize %08x\n", ptr,oldsize,size);
350     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
351
352     if (pArena->flags & GA_DOSMEM)
353     {
354         if (DOSMEM_ResizeBlock(ptr, size, TRUE) == size) 
355             newptr = ptr;
356         else if(pArena->pageLockCount > 0)
357             newptr = 0;
358         else
359         {
360             newptr = DOSMEM_AllocBlock( size, 0 );
361             if (newptr)
362             {
363                 memcpy( newptr, ptr, oldsize );
364                 DOSMEM_FreeBlock( ptr );
365             }
366         }
367     }
368     else
369     {
370         /*
371          * if more than one reader (e.g. some pointer has been 
372          * given out by GetVDMPointer32W16),
373          * only try to realloc in place
374          */
375
376         if (ptr)
377             newptr = HeapReAlloc( GetProcessHeap(),
378                 (pArena->pageLockCount > 0) ? HEAP_REALLOC_IN_PLACE_ONLY : 0, 
379                               ptr, size );
380         else
381             newptr = HeapAlloc( GetProcessHeap(),
382                 (pArena->pageLockCount > 0) ? HEAP_REALLOC_IN_PLACE_ONLY : 0, 
383                               size );
384
385     }
386
387     if (!newptr)
388     {
389         FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
390         if (pArena->pageLockCount <1)
391         {
392             if (pArena->flags & GA_DOSMEM)
393                 DOSMEM_FreeBlock( (void *)pArena->base );
394             else
395                 HeapFree( GetProcessHeap(), 0, ptr );
396             SELECTOR_FreeBlock( sel );
397             memset( pArena, 0, sizeof(GLOBALARENA) );
398         }
399         return 0;
400     }
401     ptr = newptr;
402
403       /* Reallocate the selector(s) */
404
405     sel = SELECTOR_ReallocBlock( sel, ptr, size );
406     if (!sel)
407     {
408         if (pArena->flags & GA_DOSMEM)
409             DOSMEM_FreeBlock( (void *)pArena->base );
410         else
411             HeapFree( GetProcessHeap(), 0, ptr );
412         memset( pArena, 0, sizeof(GLOBALARENA) );
413         return 0;
414     }
415     selcount = (size + 0xffff) / 0x10000;
416
417     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
418     {        
419         if (pArena->flags & GA_DOSMEM)
420             DOSMEM_FreeBlock( (void *)pArena->base );
421         else
422             HeapFree( GetProcessHeap(), 0, ptr );
423         SELECTOR_FreeBlock( sel );
424         return 0;
425     }
426
427       /* Fill the new arena block
428          As we may have used HEAP_REALLOC_IN_PLACE_ONLY, areas may overlap*/
429
430     if (pNewArena != pArena) memmove( pNewArena, pArena, sizeof(GLOBALARENA) );
431     pNewArena->base = ptr;
432     pNewArena->size = GetSelectorLimit16(sel) + 1;
433     pNewArena->selCount = selcount;
434     pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
435
436     if (selcount > 1)  /* clear the next arena blocks */
437         memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
438
439     if ((oldsize < size) && (flags & GMEM_ZEROINIT))
440         memset( (char *)ptr + oldsize, 0, size - oldsize );
441     return pNewArena->handle;
442 }
443
444
445 /***********************************************************************
446  *           GlobalFree     (KERNEL.17)
447  *           GlobalFree16   (KERNEL32.31)
448  * RETURNS
449  *      NULL: Success
450  *      Handle: Failure
451  */
452 HGLOBAL16 WINAPI GlobalFree16(
453                  HGLOBAL16 handle /* [in] Handle of global memory object */
454 ) {
455     void *ptr;
456
457     if (!VALID_HANDLE(handle))
458     {
459         WARN("Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
460         return 0;
461     }
462     ptr = (void *)GET_ARENA_PTR(handle)->base;
463
464     TRACE("%04x\n", handle );
465     if (!GLOBAL_FreeBlock( handle )) return handle;  /* failed */
466     HeapFree( GetProcessHeap(), 0, ptr );
467     return 0;
468 }
469
470
471 /**********************************************************************
472  *           K32WOWGlobalLock16         (KERNEL32.60)
473  */
474 SEGPTR WINAPI K32WOWGlobalLock16( HGLOBAL16 handle )
475 {
476     WORD sel = GlobalHandleToSel16( handle );
477     TRACE("(%04x) -> %08x\n", handle, MAKELONG( 0, sel ) );
478
479     if (handle)
480     {
481         if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
482
483         if (!VALID_HANDLE(handle)) {
484             WARN("Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
485             sel = 0;
486         }
487         else if (!GET_ARENA_PTR(handle)->base)
488             sel = 0;
489         else
490             GET_ARENA_PTR(handle)->lockCount++;
491     }
492
493     return MAKESEGPTR( sel, 0 );
494
495 }
496
497
498 /***********************************************************************
499  *           GlobalLock   (KERNEL.18)
500  *
501  * This is the GlobalLock16() function used by 16-bit code.
502  */
503 SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
504 {
505     SEGPTR ret = K32WOWGlobalLock16( handle );
506     CURRENT_STACK16->ecx = SELECTOROF(ret);  /* selector must be returned in CX as well */
507     return ret;
508 }
509
510
511 /***********************************************************************
512  *           GlobalLock16   (KERNEL32.25)
513  *
514  * This is the GlobalLock16() function used by 32-bit code.
515  *
516  * RETURNS
517  *      Pointer to first byte of memory block
518  *      NULL: Failure
519  */
520 LPVOID WINAPI GlobalLock16(
521               HGLOBAL16 handle /* [in] Handle of global memory object */
522 ) {
523     if (!handle) return 0;
524     if (!VALID_HANDLE(handle))
525         return 0;
526     GET_ARENA_PTR(handle)->lockCount++;
527     return (LPVOID)GET_ARENA_PTR(handle)->base;
528 }
529
530
531 /***********************************************************************
532  *           GlobalUnlock     (KERNEL.19)
533  *           GlobalUnlock16   (KERNEL32.26)
534  * NOTES
535  *      Should the return values be cast to booleans?
536  *
537  * RETURNS
538  *      TRUE: Object is still locked
539  *      FALSE: Object is unlocked
540  */
541 BOOL16 WINAPI GlobalUnlock16(
542               HGLOBAL16 handle /* [in] Handle of global memory object */
543 ) {
544     GLOBALARENA *pArena = GET_ARENA_PTR(handle);
545     if (!VALID_HANDLE(handle)) {
546         WARN("Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
547         return 0;
548     }
549     TRACE("%04x\n", handle );
550     if (pArena->lockCount) pArena->lockCount--;
551     return pArena->lockCount;
552 }
553
554 /***********************************************************************
555  *     GlobalChangeLockCount               (KERNEL.365)
556  *
557  * This is declared as a register function as it has to preserve
558  * *all* registers, even AX/DX !
559  *
560  */
561 void WINAPI GlobalChangeLockCount16( HGLOBAL16 handle, INT16 delta,
562                                      CONTEXT86 *context )
563 {
564     if ( delta == 1 )
565         GlobalLock16( handle );
566     else if ( delta == -1 )
567         GlobalUnlock16( handle );
568     else
569         ERR("(%04X, %d): strange delta value\n", handle, delta );
570 }
571
572 /***********************************************************************
573  *           GlobalSize     (KERNEL.20)
574  *           GlobalSize16   (KERNEL32.32)
575  * 
576  * Get the current size of a global memory object.
577  *
578  * RETURNS
579  *      Size in bytes of object
580  *      0: Failure
581  */
582 DWORD WINAPI GlobalSize16(
583              HGLOBAL16 handle /* [in] Handle of global memory object */
584 ) {
585     TRACE("%04x\n", handle );
586     if (!handle) return 0;
587     if (!VALID_HANDLE(handle))
588         return 0;
589     return GET_ARENA_PTR(handle)->size;
590 }
591
592
593 /***********************************************************************
594  *           GlobalHandle   (KERNEL.21)
595  *
596  * Get the handle associated with a pointer to the global memory block.
597  *
598  * NOTES
599  *      Why is GlobalHandleToSel used here with the sel as input?
600  *
601  * RETURNS
602  *      Handle: Success
603  *      NULL: Failure
604  */
605 DWORD WINAPI GlobalHandle16(
606              WORD sel /* [in] Address of global memory block */
607 ) {
608     TRACE("%04x\n", sel );
609     if (!VALID_HANDLE(sel)) {
610         WARN("Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
611         return 0;
612     }
613     return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
614 }
615
616 /***********************************************************************
617  *           GlobalHandleNoRIP   (KERNEL.159)
618  */
619 DWORD WINAPI GlobalHandleNoRIP16( WORD sel )
620 {
621     int i;
622     for (i = globalArenaSize-1 ; i>=0 ; i--) {
623         if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
624                 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
625     }
626     return 0;
627 }
628
629
630 /***********************************************************************
631  *           GlobalFlags     (KERNEL.22)
632  *
633  * Get information about a global memory object.
634  *
635  * NOTES
636  *      Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
637  *      handle?
638  *
639  * RETURNS
640  *      Value specifying flags and lock count
641  *      GMEM_INVALID_HANDLE: Invalid handle
642  */
643 UINT16 WINAPI GlobalFlags16(
644               HGLOBAL16 handle /* [in] Handle of global memory object */
645 ) {
646     GLOBALARENA *pArena;
647
648     TRACE("%04x\n", handle );
649     if (!VALID_HANDLE(handle)) {
650         WARN("Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
651         return 0;
652     }
653     pArena = GET_ARENA_PTR(handle);
654     return pArena->lockCount |
655            ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
656            ((pArena->base == 0) ? GMEM_DISCARDED : 0);
657 }
658
659
660 /***********************************************************************
661  *           LockSegment   (KERNEL.23)
662  */
663 HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
664 {
665     TRACE("%04x\n", handle );
666     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
667     if (!VALID_HANDLE(handle)) {
668         WARN("Invalid handle 0x%04x passed to LockSegment16!\n",handle);
669         return 0;
670     }
671     GET_ARENA_PTR(handle)->lockCount++;
672     return handle;
673 }
674
675
676 /***********************************************************************
677  *           UnlockSegment   (KERNEL.24)
678  */
679 void WINAPI UnlockSegment16( HGLOBAL16 handle )
680 {
681     TRACE("%04x\n", handle );
682     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
683     if (!VALID_HANDLE(handle)) {
684         WARN("Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
685         return;
686     }
687     GET_ARENA_PTR(handle)->lockCount--;
688     /* FIXME: this ought to return the lock count in CX (go figure...) */
689 }
690
691
692 /***********************************************************************
693  *           GlobalCompact   (KERNEL.25)
694  */
695 DWORD WINAPI GlobalCompact16( DWORD desired )
696 {
697     return GLOBAL_MAX_ALLOC_SIZE;
698 }
699
700
701 /***********************************************************************
702  *           GlobalFreeAll   (KERNEL.26)
703  */
704 void WINAPI GlobalFreeAll16( HGLOBAL16 owner )
705 {
706     int i;
707     GLOBALARENA *pArena;
708
709     pArena = pGlobalArena;
710     for (i = 0; i < globalArenaSize; i++, pArena++)
711     {
712         if ((pArena->size != 0) && (pArena->hOwner == owner))
713             GlobalFree16( pArena->handle );
714     }
715 }
716
717
718 /***********************************************************************
719  *           GlobalWire     (KERNEL.111)
720  *           GlobalWire16   (KERNEL32.29)
721  */
722 SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
723 {
724     return WIN16_GlobalLock16( handle );
725 }
726
727
728 /***********************************************************************
729  *           GlobalUnWire     (KERNEL.112)
730  *           GlobalUnWire16   (KERNEL32.30)
731  */
732 BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
733 {
734     return !GlobalUnlock16( handle );
735 }
736
737
738 /***********************************************************************
739  *           SetSwapAreaSize   (KERNEL.106)
740  */
741 LONG WINAPI SetSwapAreaSize16( WORD size )
742 {
743     FIXME("(%d) - stub!\n", size );
744     return MAKELONG( size, 0xffff );
745 }
746
747
748 /***********************************************************************
749  *           GlobalLRUOldest   (KERNEL.163)
750  */
751 HGLOBAL16 WINAPI GlobalLRUOldest16( HGLOBAL16 handle )
752 {
753     TRACE("%04x\n", handle );
754     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
755     return handle;
756 }
757
758
759 /***********************************************************************
760  *           GlobalLRUNewest   (KERNEL.164)
761  */
762 HGLOBAL16 WINAPI GlobalLRUNewest16( HGLOBAL16 handle )
763 {
764     TRACE("%04x\n", handle );
765     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
766     return handle;
767 }
768
769
770 /***********************************************************************
771  *           GetFreeSpace   (KERNEL.169)
772  */
773 DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
774 {
775     MEMORYSTATUS ms;
776     GlobalMemoryStatus( &ms );
777     return ms.dwAvailVirtual;
778 }
779
780 /***********************************************************************
781  *           GlobalDOSAlloc   (KERNEL.184)
782  *
783  * Allocate memory in the first MB.
784  *
785  * RETURNS
786  *      Address (HW=Paragraph segment; LW=Selector)
787  */
788 DWORD WINAPI GlobalDOSAlloc16(
789              DWORD size /* [in] Number of bytes to be allocated */
790 ) {
791    UINT16    uParagraph;
792    LPVOID    lpBlock = DOSMEM_AllocBlock( size, &uParagraph );
793
794    if( lpBlock )
795    {
796        HMODULE16 hModule = GetModuleHandle16("KERNEL");
797        WORD      wSelector;
798        GLOBALARENA *pArena;
799
800        wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, hModule, WINE_LDT_FLAGS_DATA );
801        pArena = GET_ARENA_PTR(wSelector);
802        pArena->flags |= GA_DOSMEM;
803        return MAKELONG(wSelector,uParagraph);
804    }
805    return 0;
806 }
807
808
809 /***********************************************************************
810  *           GlobalDOSFree      (KERNEL.185)
811  *
812  * Free memory allocated with GlobalDOSAlloc
813  *
814  * RETURNS
815  *      NULL: Success
816  *      sel: Failure
817  */
818 WORD WINAPI GlobalDOSFree16(
819             WORD sel /* [in] Selector */
820 ) {
821    DWORD   block = GetSelectorBase(sel);
822
823    if( block && block < 0x100000 )
824    {
825        LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
826        if( DOSMEM_FreeBlock( lpBlock ) )
827            GLOBAL_FreeBlock( sel );
828        sel = 0;
829    }
830    return sel;
831 }
832
833
834 /***********************************************************************
835  *           GlobalPageLock   (KERNEL.191)
836  *           GlobalSmartPageLock(KERNEL.230)
837  */
838 WORD WINAPI GlobalPageLock16( HGLOBAL16 handle )
839 {
840     TRACE("%04x\n", handle );
841     if (!VALID_HANDLE(handle)) {
842         WARN("Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
843         return 0;
844     }
845     return ++(GET_ARENA_PTR(handle)->pageLockCount);
846 }
847
848
849 /***********************************************************************
850  *           GlobalPageUnlock   (KERNEL.192)
851  *           GlobalSmartPageUnlock(KERNEL.231)
852  */
853 WORD WINAPI GlobalPageUnlock16( HGLOBAL16 handle )
854 {
855     TRACE("%04x\n", handle );
856     if (!VALID_HANDLE(handle)) {
857         WARN("Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
858         return 0;
859     }
860     return --(GET_ARENA_PTR(handle)->pageLockCount);
861 }
862
863
864 /***********************************************************************
865  *           GlobalFix     (KERNEL.197)
866  *           GlobalFix16   (KERNEL32.27)
867  */
868 WORD WINAPI GlobalFix16( HGLOBAL16 handle )
869 {
870     TRACE("%04x\n", handle );
871     if (!VALID_HANDLE(handle)) {
872         WARN("Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
873         return 0;
874     }
875     GET_ARENA_PTR(handle)->lockCount++;
876
877     return GlobalHandleToSel16(handle);
878 }
879
880
881 /***********************************************************************
882  *           GlobalUnfix     (KERNEL.198)
883  *           GlobalUnfix16   (KERNEL32.28)
884  */
885 void WINAPI GlobalUnfix16( HGLOBAL16 handle )
886 {
887     TRACE("%04x\n", handle );
888     if (!VALID_HANDLE(handle)) {
889         WARN("Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
890         return;
891     }
892     GET_ARENA_PTR(handle)->lockCount--;
893 }
894
895
896 /***********************************************************************
897  *           FarSetOwner   (KERNEL.403)
898  */
899 void WINAPI FarSetOwner16( HGLOBAL16 handle, HANDLE16 hOwner )
900 {
901     if (!VALID_HANDLE(handle)) {
902         WARN("Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
903         return;
904     }
905     GET_ARENA_PTR(handle)->hOwner = hOwner;
906 }
907
908
909 /***********************************************************************
910  *           FarGetOwner   (KERNEL.404)
911  */
912 HANDLE16 WINAPI FarGetOwner16( HGLOBAL16 handle )
913 {
914     if (!VALID_HANDLE(handle)) {
915         WARN("Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
916         return 0;
917     }
918     return GET_ARENA_PTR(handle)->hOwner;
919 }
920
921
922 /************************************************************************
923  *              GlobalMasterHandle (KERNEL.28)
924  *
925  *
926  * Should return selector and handle of the information structure for
927  * the global heap. selector and handle are stored in the THHOOK as
928  * pGlobalHeap and hGlobalHeap.
929  * As Wine doesn't have this structure, we return both values as zero
930  * Applications should interpret this as "No Global Heap"
931  */
932 DWORD WINAPI GlobalMasterHandle16(void)
933 {
934     FIXME(": stub\n");
935     return 0;
936 }
937
938 /***********************************************************************
939  *           GlobalHandleToSel   (TOOLHELP.50)
940  */
941 WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
942 {
943     if (!handle) return 0;
944     if (!VALID_HANDLE(handle)) {
945         WARN("Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
946         return 0;
947     }
948     if (!(handle & 7))
949     {
950         WARN("Program attempted invalid selector conversion\n" );
951         return handle - 1;
952     }
953     return handle | 7;
954 }
955
956
957 /***********************************************************************
958  *           GlobalFirst   (TOOLHELP.51)
959  */
960 BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
961 {
962     if (wFlags == GLOBAL_LRU) return FALSE;
963     pGlobal->dwNext = 0;
964     return GlobalNext16( pGlobal, wFlags );
965 }
966
967
968 /***********************************************************************
969  *           GlobalNext   (TOOLHELP.52)
970  */
971 BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
972 {
973     GLOBALARENA *pArena;
974
975     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
976     pArena = pGlobalArena + pGlobal->dwNext;
977     if (wFlags == GLOBAL_FREE)  /* only free blocks */
978     {
979         int i;
980         for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
981             if (pArena->size == 0) break;  /* block is free */
982         if (i >= globalArenaSize) return FALSE;
983         pGlobal->dwNext = i;
984     }
985
986     pGlobal->dwAddress    = (DWORD_PTR)pArena->base;
987     pGlobal->dwBlockSize  = pArena->size;
988     pGlobal->hBlock       = pArena->handle;
989     pGlobal->wcLock       = pArena->lockCount;
990     pGlobal->wcPageLock   = pArena->pageLockCount;
991     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
992     pGlobal->wHeapPresent = FALSE;
993     pGlobal->hOwner       = pArena->hOwner;
994     pGlobal->wType        = GT_UNKNOWN;
995     pGlobal->wData        = 0;
996     pGlobal->dwNext++;
997     return TRUE;
998 }
999
1000
1001 /***********************************************************************
1002  *           GlobalInfo   (TOOLHELP.53)
1003  */
1004 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
1005 {
1006     int i;
1007     GLOBALARENA *pArena;
1008
1009     pInfo->wcItems = globalArenaSize;
1010     pInfo->wcItemsFree = 0;
1011     pInfo->wcItemsLRU = 0;
1012     for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
1013         if (pArena->size == 0) pInfo->wcItemsFree++;
1014     return TRUE;
1015 }
1016
1017
1018 /***********************************************************************
1019  *           GlobalEntryHandle   (TOOLHELP.54)
1020  */
1021 BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
1022 {
1023     GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
1024
1025     pGlobal->dwAddress    = (DWORD_PTR)pArena->base;
1026     pGlobal->dwBlockSize  = pArena->size;
1027     pGlobal->hBlock       = pArena->handle;
1028     pGlobal->wcLock       = pArena->lockCount;
1029     pGlobal->wcPageLock   = pArena->pageLockCount;
1030     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
1031     pGlobal->wHeapPresent = FALSE;
1032     pGlobal->hOwner       = pArena->hOwner;
1033     pGlobal->wType        = GT_UNKNOWN;
1034     pGlobal->wData        = 0;
1035     pGlobal->dwNext++;
1036     return TRUE;
1037 }
1038
1039
1040 /***********************************************************************
1041  *           GlobalEntryModule   (TOOLHELP.55)
1042  */
1043 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
1044                                  WORD wSeg )
1045 {
1046     FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
1047     return FALSE;
1048 }
1049
1050
1051 /***********************************************************************
1052  *           MemManInfo   (TOOLHELP.72)
1053  */
1054 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
1055 {
1056     MEMORYSTATUS status;
1057
1058     /*
1059      * Not unsurprisingly although the documention says you
1060      * _must_ provide the size in the dwSize field, this function
1061      * (under Windows) always fills the structure and returns true.
1062      */
1063     GlobalMemoryStatus( &status );
1064     info->wPageSize            = getpagesize();
1065     info->dwLargestFreeBlock   = status.dwAvailVirtual;
1066     info->dwMaxPagesAvailable  = info->dwLargestFreeBlock / info->wPageSize;
1067     info->dwMaxPagesLockable   = info->dwMaxPagesAvailable;
1068     info->dwTotalLinearSpace   = status.dwTotalVirtual / info->wPageSize;
1069     info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
1070     info->dwFreePages          = info->dwMaxPagesAvailable;
1071     info->dwTotalPages         = info->dwTotalLinearSpace;
1072     info->dwFreeLinearSpace    = info->dwMaxPagesAvailable;
1073     info->dwSwapFilePages      = status.dwTotalPageFile / info->wPageSize;
1074     return TRUE;
1075 }
1076
1077 /***********************************************************************
1078  *           GetFreeMemInfo   (KERNEL.316)
1079  */
1080 DWORD WINAPI GetFreeMemInfo16(void)
1081 {
1082     MEMMANINFO info;
1083     MemManInfo16( &info );
1084     return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
1085 }
1086
1087 /***********************************************************************
1088  *           A20Proc   (KERNEL.165)
1089  */
1090 void WINAPI A20Proc16( WORD unused )
1091 {
1092     /* this is also a NOP in Windows */
1093 }
1094
1095 /***********************************************************************
1096  *           LimitEMSPages   (KERNEL.156)
1097  */
1098 DWORD WINAPI LimitEMSPages16( DWORD unused )
1099 {
1100     return 0;
1101 }