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