~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/global16.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

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