include: Make RpcRaiseException DECLSPEC_NORETURN, like it is in the PSDK.
[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 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)
981 {
982     GLOBALARENA *pArena;
983
984     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
985     pArena = pGlobalArena + pGlobal->dwNext;
986     if (wFlags == GLOBAL_FREE)  /* only free blocks */
987     {
988         int i;
989         for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
990             if (pArena->size == 0) break;  /* block is free */
991         if (i >= globalArenaSize) return FALSE;
992         pGlobal->dwNext = i;
993     }
994
995     pGlobal->dwAddress    = (DWORD_PTR)pArena->base;
996     pGlobal->dwBlockSize  = pArena->size;
997     pGlobal->hBlock       = pArena->handle;
998     pGlobal->wcLock       = pArena->lockCount;
999     pGlobal->wcPageLock   = pArena->pageLockCount;
1000     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
1001     pGlobal->wHeapPresent = FALSE;
1002     pGlobal->hOwner       = pArena->hOwner;
1003     pGlobal->wType        = GT_UNKNOWN;
1004     pGlobal->wData        = 0;
1005     pGlobal->dwNext++;
1006     return TRUE;
1007 }
1008
1009
1010 /***********************************************************************
1011  *           GlobalInfo   (TOOLHELP.53)
1012  */
1013 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
1014 {
1015     int i;
1016     GLOBALARENA *pArena;
1017
1018     pInfo->wcItems = globalArenaSize;
1019     pInfo->wcItemsFree = 0;
1020     pInfo->wcItemsLRU = 0;
1021     for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
1022         if (pArena->size == 0) pInfo->wcItemsFree++;
1023     return TRUE;
1024 }
1025
1026
1027 /***********************************************************************
1028  *           GlobalEntryHandle   (TOOLHELP.54)
1029  */
1030 BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
1031 {
1032     GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
1033
1034     pGlobal->dwAddress    = (DWORD_PTR)pArena->base;
1035     pGlobal->dwBlockSize  = pArena->size;
1036     pGlobal->hBlock       = pArena->handle;
1037     pGlobal->wcLock       = pArena->lockCount;
1038     pGlobal->wcPageLock   = pArena->pageLockCount;
1039     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
1040     pGlobal->wHeapPresent = FALSE;
1041     pGlobal->hOwner       = pArena->hOwner;
1042     pGlobal->wType        = GT_UNKNOWN;
1043     pGlobal->wData        = 0;
1044     pGlobal->dwNext++;
1045     return TRUE;
1046 }
1047
1048
1049 /***********************************************************************
1050  *           GlobalEntryModule   (TOOLHELP.55)
1051  */
1052 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
1053                                  WORD wSeg )
1054 {
1055     FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
1056     return FALSE;
1057 }
1058
1059
1060 /***********************************************************************
1061  *           MemManInfo   (TOOLHELP.72)
1062  */
1063 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
1064 {
1065     MEMORYSTATUS status;
1066
1067     /*
1068      * Not unsurprisingly although the documention says you
1069      * _must_ provide the size in the dwSize field, this function
1070      * (under Windows) always fills the structure and returns true.
1071      */
1072     GlobalMemoryStatus( &status );
1073     info->wPageSize            = getpagesize();
1074     info->dwLargestFreeBlock   = status.dwAvailVirtual;
1075     info->dwMaxPagesAvailable  = info->dwLargestFreeBlock / info->wPageSize;
1076     info->dwMaxPagesLockable   = info->dwMaxPagesAvailable;
1077     info->dwTotalLinearSpace   = status.dwTotalVirtual / info->wPageSize;
1078     info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
1079     info->dwFreePages          = info->dwMaxPagesAvailable;
1080     info->dwTotalPages         = info->dwTotalLinearSpace;
1081     info->dwFreeLinearSpace    = info->dwMaxPagesAvailable;
1082     info->dwSwapFilePages      = status.dwTotalPageFile / info->wPageSize;
1083     return TRUE;
1084 }
1085
1086 /***********************************************************************
1087  *           GetFreeMemInfo   (KERNEL.316)
1088  */
1089 DWORD WINAPI GetFreeMemInfo16(void)
1090 {
1091     MEMMANINFO info;
1092     MemManInfo16( &info );
1093     return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
1094 }
1095
1096 /***********************************************************************
1097  *           A20Proc   (KERNEL.165)
1098  */
1099 void WINAPI A20Proc16( WORD unused )
1100 {
1101     /* this is also a NOP in Windows */
1102 }
1103
1104 /***********************************************************************
1105  *           LimitEMSPages   (KERNEL.156)
1106  */
1107 DWORD WINAPI LimitEMSPages16( DWORD unused )
1108 {
1109     return 0;
1110 }