Release 980913
[wine/multimedia.git] / memory / global.c
blobfd8bb5b5d14e9038e2eeb6302020281303483cd0
1 /*
2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <sys/types.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
12 #include "windows.h"
13 #include "global.h"
14 #include "heap.h"
15 #include "toolhelp.h"
16 #include "selectors.h"
17 #include "miscemu.h"
18 #include "dde_mem.h"
19 #include "stackframe.h"
20 #include "module.h"
21 #include "debug.h"
22 #include "winerror.h"
24 /* Global arena block */
25 typedef struct
27 DWORD base; /* Base address (0 if discarded) */
28 DWORD size; /* Size in bytes (0 indicates a free block) */
29 HGLOBAL16 handle; /* Handle for this block */
30 HGLOBAL16 hOwner; /* Owner of this block */
31 BYTE lockCount; /* Count of GlobalFix() calls */
32 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
33 BYTE flags; /* Allocation flags */
34 BYTE selCount; /* Number of selectors allocated for this block */
35 #ifdef CONFIG_IPC
36 int shmid;
37 #endif
38 } GLOBALARENA;
40 /* Flags definitions */
41 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
42 #define GA_DGROUP 0x04
43 #define GA_DISCARDABLE 0x08
44 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
46 /* Arena array */
47 static GLOBALARENA *pGlobalArena = NULL;
48 static int globalArenaSize = 0;
50 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
52 #define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
53 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
55 /***********************************************************************
56 * GLOBAL_GetArena
58 * Return the arena for a given selector, growing the arena array if needed.
60 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
62 if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
64 int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
65 GLOBALARENA *pNewArena = realloc( pGlobalArena,
66 newsize * sizeof(GLOBALARENA) );
67 if (!pNewArena) return 0;
68 pGlobalArena = pNewArena;
69 memset( pGlobalArena + globalArenaSize, 0,
70 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
71 globalArenaSize = newsize;
73 return pGlobalArena + (sel >> __AHSHIFT);
77 void debug_handles()
79 int printed=0;
80 int i;
81 for (i = globalArenaSize-1 ; i>=0 ; i--) {
82 if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
83 printed=1;
84 DUMP("0x%08x, ",pGlobalArena[i].handle);
87 if (printed)
88 DUMP("\n");
92 /***********************************************************************
93 * GLOBAL_CreateBlock
95 * Create a global heap block for a fixed range of linear memory.
97 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
98 HGLOBAL16 hOwner, BOOL16 isCode,
99 BOOL16 is32Bit, BOOL16 isReadOnly,
100 SHMDATA *shmdata )
102 WORD sel, selcount;
103 GLOBALARENA *pArena;
105 /* Allocate the selector(s) */
107 sel = SELECTOR_AllocBlock( ptr, size,
108 isCode ? SEGMENT_CODE : SEGMENT_DATA,
109 is32Bit, isReadOnly );
111 if (!sel) return 0;
112 selcount = (size + 0xffff) / 0x10000;
114 if (!(pArena = GLOBAL_GetArena( sel, selcount )))
116 SELECTOR_FreeBlock( sel, selcount );
117 return 0;
120 /* Fill the arena block */
122 pArena->base = (DWORD)ptr;
123 pArena->size = GET_SEL_LIMIT(sel) + 1;
125 #ifdef CONFIG_IPC
126 if (flags & GMEM_DDESHARE)
128 pArena->handle = shmdata->handle;
129 pArena->shmid = shmdata->shmid;
130 shmdata->sel = sel;
132 else
134 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
135 pArena->shmid = 0;
137 #else
138 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
139 #endif
140 pArena->hOwner = hOwner;
141 pArena->lockCount = 0;
142 pArena->pageLockCount = 0;
143 pArena->flags = flags & GA_MOVEABLE;
144 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
145 if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
146 if (!isCode) pArena->flags |= GA_DGROUP;
147 pArena->selCount = selcount;
148 if (selcount > 1) /* clear the next arena blocks */
149 memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
151 return pArena->handle;
155 /***********************************************************************
156 * GLOBAL_FreeBlock
158 * Free a block allocated by GLOBAL_CreateBlock, without touching
159 * the associated linear memory range.
161 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
163 WORD sel;
164 GLOBALARENA *pArena;
166 if (!handle) return TRUE;
167 sel = GlobalHandleToSel( handle );
168 if (!VALID_HANDLE(sel))
169 return FALSE;
170 pArena = GET_ARENA_PTR(sel);
171 SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
172 memset( pArena, 0, sizeof(GLOBALARENA) );
173 return TRUE;
177 /***********************************************************************
178 * GLOBAL_Alloc
180 * Implementation of GlobalAlloc16()
182 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
183 BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
185 void *ptr;
186 HGLOBAL16 handle;
187 SHMDATA shmdata;
189 TRACE(global, "%ld flags=%04x\n", size, flags );
191 /* If size is 0, create a discarded block */
193 if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
194 is32Bit, isReadOnly, NULL );
196 /* Fixup the size */
198 if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
199 size = (size + 0x1f) & ~0x1f;
201 /* Allocate the linear memory */
203 #ifdef CONFIG_IPC
204 if (flags & GMEM_DDESHARE)
205 ptr = DDE_malloc(flags, size, &shmdata);
206 else
207 #endif /* CONFIG_IPC */
209 ptr = HeapAlloc( SystemHeap, 0, size );
211 /* FIXME: free discardable blocks and try again? */
212 if (!ptr) return 0;
214 /* Allocate the selector(s) */
216 handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
217 isCode, is32Bit, isReadOnly, &shmdata);
218 if (!handle)
220 HeapFree( SystemHeap, 0, ptr );
221 return 0;
224 if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
225 return handle;
229 #ifdef CONFIG_IPC
230 /***********************************************************************
231 * GLOBAL_FindArena
233 * Find the arena for a given handle
234 * (when handle is not serial - e.g. DDE)
236 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
238 int i;
239 for (i = globalArenaSize-1 ; i>=0 ; i--) {
240 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
241 return ( &pGlobalArena[i] );
243 return NULL;
247 /***********************************************************************
248 * DDE_GlobalHandleToSel
251 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
253 GLOBALARENA *pArena;
254 SEGPTR segptr;
256 pArena= GLOBAL_FindArena(handle);
257 if (pArena) {
258 int ArenaIdx = pArena - pGlobalArena;
260 /* See if synchronized to the shared memory */
261 return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
264 /* attach the block */
265 DDE_AttachHandle(handle, &segptr);
267 return SELECTOROF( segptr );
269 #endif /* CONFIG_IPC */
272 /***********************************************************************
273 * GlobalAlloc16 (KERNEL.15)
274 * RETURNS
275 * Handle: Success
276 * NULL: Failure
278 HGLOBAL16 WINAPI GlobalAlloc16(
279 UINT16 flags, /* [in] Object allocation attributes */
280 DWORD size /* [in] Number of bytes to allocate */
282 HANDLE16 owner = GetCurrentPDB();
284 if (flags & GMEM_DDESHARE)
285 owner = GetExePtr(owner); /* Make it a module handle */
286 return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
290 /***********************************************************************
291 * GlobalReAlloc16 (KERNEL.16)
292 * RETURNS
293 * Handle: Success
294 * NULL: Failure
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 */
301 WORD selcount;
302 DWORD oldsize;
303 void *ptr;
304 GLOBALARENA *pArena, *pNewArena;
305 WORD sel = GlobalHandleToSel( handle );
307 TRACE(global, "%04x %ld flags=%04x\n",
308 handle, size, flags );
309 if (!handle) return 0;
311 #ifdef CONFIG_IPC
312 if (flags & GMEM_DDESHARE || is_dde_handle(handle))
314 FIXME(global, "shared memory reallocating unimplemented\n");
315 return 0;
317 #endif /* CONFIG_IPC */
319 if (!VALID_HANDLE(handle)) {
320 WARN(global, "Invalid handle 0x%04x!\n", handle);
321 return 0;
323 pArena = GET_ARENA_PTR( handle );
325 /* Discard the block if requested */
327 if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
329 if (!(pArena->flags & GA_MOVEABLE) ||
330 !(pArena->flags & GA_DISCARDABLE) ||
331 (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
332 HeapFree( SystemHeap, 0, (void *)pArena->base );
333 pArena->base = 0;
335 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't
336 * change the selector if we are shrinking the block.
337 * FIXME: shouldn't we keep selectors until the block is deleted?
339 SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
340 return handle;
343 /* Fixup the size */
345 if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
346 if (size == 0) size = 0x20;
347 else size = (size + 0x1f) & ~0x1f;
349 /* Change the flags */
351 if (flags & GMEM_MODIFY)
353 /* Change the flags, leaving GA_DGROUP alone */
354 pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
355 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
356 return handle;
359 /* Reallocate the linear memory */
361 ptr = (void *)pArena->base;
362 oldsize = pArena->size;
363 TRACE(global,"oldsize %08lx\n",oldsize);
364 if (ptr && (size == oldsize)) return handle; /* Nothing to do */
366 ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
367 if (!ptr)
369 SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
370 memset( pArena, 0, sizeof(GLOBALARENA) );
371 return 0;
374 /* Reallocate the selector(s) */
376 sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
377 if (!sel)
379 HeapFree( SystemHeap, 0, ptr );
380 memset( pArena, 0, sizeof(GLOBALARENA) );
381 return 0;
383 selcount = (size + 0xffff) / 0x10000;
385 if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
387 HeapFree( SystemHeap, 0, ptr );
388 SELECTOR_FreeBlock( sel, selcount );
389 return 0;
392 /* Fill the new arena block */
394 if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
395 pNewArena->base = (DWORD)ptr;
396 pNewArena->size = GET_SEL_LIMIT(sel) + 1;
397 pNewArena->selCount = selcount;
398 pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
400 if (selcount > 1) /* clear the next arena blocks */
401 memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
403 if ((oldsize < size) && (flags & GMEM_ZEROINIT))
404 memset( (char *)ptr + oldsize, 0, size - oldsize );
405 return pNewArena->handle;
409 /***********************************************************************
410 * GlobalFree16 (KERNEL.17)
411 * RETURNS
412 * NULL: Success
413 * Handle: Failure
415 HGLOBAL16 WINAPI GlobalFree16(
416 HGLOBAL16 handle /* [in] Handle of global memory object */
418 void *ptr;
420 if (!VALID_HANDLE(handle)) {
421 WARN(global,"Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
422 return 0;
424 ptr = (void *)GET_ARENA_PTR(handle)->base;
426 TRACE(global, "%04x\n", handle );
427 if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
428 #ifdef CONFIG_IPC
429 if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
430 #endif /* CONFIG_IPC */
431 if (ptr) HeapFree( SystemHeap, 0, ptr );
432 return 0;
436 /***********************************************************************
437 * WIN16_GlobalLock16 (KERNEL.18)
439 * This is the GlobalLock16() function used by 16-bit code.
441 SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
443 TRACE(global, "(%04x) -> %08lx\n",
444 handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
445 if (handle)
447 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
449 #ifdef CONFIG_IPC
450 if (is_dde_handle(handle))
451 return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
452 #endif /* CONFIG_IPC */
454 if (!VALID_HANDLE(handle)) {
455 WARN(global,"Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
456 return (SEGPTR)0;
458 if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
459 GET_ARENA_PTR(handle)->lockCount++;
460 return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
461 /* FIXME: put segment value in CX as well */
463 return (SEGPTR)0;
467 /***********************************************************************
468 * GlobalLock16 (KERNEL.18)
470 * This is the GlobalLock16() function used by 32-bit code.
472 * RETURNS
473 * Pointer to first byte of memory block
474 * NULL: Failure
476 LPVOID WINAPI GlobalLock16(
477 HGLOBAL16 handle /* [in] Handle of global memory object */
479 if (!handle) return 0;
480 if (!VALID_HANDLE(handle))
481 return (LPVOID)0;
482 GET_ARENA_PTR(handle)->lockCount++;
483 #ifdef CONFIG_IPC
484 if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
485 #endif
486 return (LPVOID)GET_ARENA_PTR(handle)->base;
490 /***********************************************************************
491 * GlobalUnlock16 (KERNEL.19)
492 * NOTES
493 * Should the return values be cast to booleans?
495 * RETURNS
496 * TRUE: Object is still locked
497 * FALSE: Object is unlocked
499 BOOL16 WINAPI GlobalUnlock16(
500 HGLOBAL16 handle /* [in] Handle of global memory object */
502 GLOBALARENA *pArena = GET_ARENA_PTR(handle);
503 if (!VALID_HANDLE(handle)) {
504 WARN(global,"Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
505 return 0;
507 TRACE(global, "%04x\n", handle );
508 if (pArena->lockCount) pArena->lockCount--;
509 return pArena->lockCount;
513 /***********************************************************************
514 * GlobalSize16 (KERNEL.20)
515 * RETURNS
516 * Size in bytes of object
517 * 0: Failure
519 DWORD WINAPI GlobalSize16(
520 HGLOBAL16 handle /* [in] Handle of global memory object */
522 TRACE(global, "%04x\n", handle );
523 if (!handle) return 0;
524 if (!VALID_HANDLE(handle))
525 return 0;
526 return GET_ARENA_PTR(handle)->size;
530 /***********************************************************************
531 * GlobalHandle16 (KERNEL.21)
532 * NOTES
533 * Why is GlobalHandleToSel used here with the sel as input?
535 * RETURNS
536 * Handle: Success
537 * NULL: Failure
539 DWORD WINAPI GlobalHandle16(
540 WORD sel /* [in] Address of global memory block */
542 TRACE(global, "%04x\n", sel );
543 if (!VALID_HANDLE(sel)) {
544 WARN(global,"Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
545 return 0;
547 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
550 /***********************************************************************
551 * GlobalHandleNoRIP (KERNEL.159)
553 DWORD WINAPI GlobalHandleNoRIP( WORD sel )
555 int i;
556 for (i = globalArenaSize-1 ; i>=0 ; i--) {
557 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
558 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
560 return 0;
564 /***********************************************************************
565 * GlobalFlags16 (KERNEL.22)
566 * NOTES
567 * Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
568 * handle?
570 * RETURNS
571 * Value specifying flags and lock count
572 * GMEM_INVALID_HANDLE: Invalid handle
574 UINT16 WINAPI GlobalFlags16(
575 HGLOBAL16 handle /* [in] Handle of global memory object */
577 GLOBALARENA *pArena;
579 TRACE(global, "%04x\n", handle );
580 if (!VALID_HANDLE(handle)) {
581 WARN(global,"Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
582 return 0;
584 pArena = GET_ARENA_PTR(handle);
585 return pArena->lockCount |
586 ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
587 ((pArena->base == 0) ? GMEM_DISCARDED : 0);
591 /***********************************************************************
592 * LockSegment16 (KERNEL.23)
594 HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
596 TRACE(global, "%04x\n", handle );
597 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
598 if (!VALID_HANDLE(handle)) {
599 WARN(global,"Invalid handle 0x%04x passed to LockSegment16!\n",handle);
600 return 0;
602 GET_ARENA_PTR(handle)->lockCount++;
603 return handle;
607 /***********************************************************************
608 * UnlockSegment16 (KERNEL.24)
610 void WINAPI UnlockSegment16( HGLOBAL16 handle )
612 TRACE(global, "%04x\n", handle );
613 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
614 if (!VALID_HANDLE(handle)) {
615 WARN(global,"Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
616 return;
618 GET_ARENA_PTR(handle)->lockCount--;
619 /* FIXME: this ought to return the lock count in CX (go figure...) */
623 /***********************************************************************
624 * GlobalCompact16 (KERNEL.25)
626 DWORD WINAPI GlobalCompact16( DWORD desired )
628 return GLOBAL_MAX_ALLOC_SIZE;
632 /***********************************************************************
633 * GlobalFreeAll (KERNEL.26)
635 void WINAPI GlobalFreeAll( HGLOBAL16 owner )
637 DWORD i;
638 GLOBALARENA *pArena;
640 pArena = pGlobalArena;
641 for (i = 0; i < globalArenaSize; i++, pArena++)
643 if ((pArena->size != 0) && (pArena->hOwner == owner))
644 GlobalFree16( pArena->handle );
649 /***********************************************************************
650 * GlobalWire16 (KERNEL.111)
652 SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
654 return WIN16_GlobalLock16( handle );
658 /***********************************************************************
659 * GlobalUnWire16 (KERNEL.112)
661 BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
663 return !GlobalUnlock16( handle );
667 /***********************************************************************
668 * SetSwapAreaSize16 (KERNEL.106)
670 LONG WINAPI SetSwapAreaSize16( WORD size )
672 FIXME(global, "(%d) - stub!\n", size );
673 return MAKELONG( size, 0xffff );
677 /***********************************************************************
678 * GlobalLRUOldest (KERNEL.163)
680 HGLOBAL16 WINAPI GlobalLRUOldest( HGLOBAL16 handle )
682 TRACE(global, "%04x\n", handle );
683 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
684 return handle;
688 /***********************************************************************
689 * GlobalLRUNewest (KERNEL.164)
691 HGLOBAL16 WINAPI GlobalLRUNewest( HGLOBAL16 handle )
693 TRACE(global, "%04x\n", handle );
694 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
695 return handle;
699 /***********************************************************************
700 * GetFreeSpace16 (KERNEL.169)
702 DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
704 MEMORYSTATUS ms;
705 GlobalMemoryStatus( &ms );
706 return ms.dwAvailVirtual;
709 /***********************************************************************
710 * GlobalDOSAlloc (KERNEL.184)
711 * RETURNS
712 * Address (HW=Paragraph segment; LW=Selector)
714 DWORD WINAPI GlobalDOSAlloc(
715 DWORD size /* [in] Number of bytes to be allocated */
717 UINT16 uParagraph;
718 LPVOID lpBlock = DOSMEM_GetBlock( 0, size, &uParagraph );
720 if( lpBlock )
722 HMODULE16 hModule = GetModuleHandle16("KERNEL");
723 WORD wSelector;
725 wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size,
726 hModule, 0, 0, 0, NULL );
727 return MAKELONG(wSelector,uParagraph);
729 return 0;
733 /***********************************************************************
734 * GlobalDOSFree (KERNEL.185)
735 * RETURNS
736 * NULL: Success
737 * sel: Failure
739 WORD WINAPI GlobalDOSFree(
740 WORD sel /* [in] Selector */
742 DWORD block = GetSelectorBase(sel);
744 if( block && block < 0x100000 )
746 LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
747 if( DOSMEM_FreeBlock( 0, lpBlock ) )
748 GLOBAL_FreeBlock( sel );
749 sel = 0;
751 return sel;
755 /***********************************************************************
756 * GlobalPageLock (KERNEL.191)
758 WORD WINAPI GlobalPageLock( HGLOBAL16 handle )
760 TRACE(global, "%04x\n", handle );
761 if (!VALID_HANDLE(handle)) {
762 WARN(global,"Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
763 return 0;
765 return ++(GET_ARENA_PTR(handle)->pageLockCount);
769 /***********************************************************************
770 * GlobalPageUnlock (KERNEL.192)
772 WORD WINAPI GlobalPageUnlock( HGLOBAL16 handle )
774 TRACE(global, "%04x\n", handle );
775 if (!VALID_HANDLE(handle)) {
776 WARN(global,"Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
777 return 0;
779 return --(GET_ARENA_PTR(handle)->pageLockCount);
783 /***********************************************************************
784 * GlobalFix16 (KERNEL.197)
786 void WINAPI GlobalFix16( HGLOBAL16 handle )
788 TRACE(global, "%04x\n", handle );
789 if (!VALID_HANDLE(handle)) {
790 WARN(global,"Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
791 return;
793 GET_ARENA_PTR(handle)->lockCount++;
797 /***********************************************************************
798 * GlobalUnfix16 (KERNEL.198)
800 void WINAPI GlobalUnfix16( HGLOBAL16 handle )
802 TRACE(global, "%04x\n", handle );
803 if (!VALID_HANDLE(handle)) {
804 WARN(global,"Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
805 return;
807 GET_ARENA_PTR(handle)->lockCount--;
811 /***********************************************************************
812 * FarSetOwner (KERNEL.403)
814 void WINAPI FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
816 if (!VALID_HANDLE(handle)) {
817 WARN(global,"Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
818 return;
820 GET_ARENA_PTR(handle)->hOwner = hOwner;
824 /***********************************************************************
825 * FarGetOwner (KERNEL.404)
827 HANDLE16 WINAPI FarGetOwner( HGLOBAL16 handle )
829 if (!VALID_HANDLE(handle)) {
830 WARN(global,"Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
831 return 0;
833 return GET_ARENA_PTR(handle)->hOwner;
837 /***********************************************************************
838 * GlobalHandleToSel (TOOLHELP.50)
840 WORD WINAPI GlobalHandleToSel( HGLOBAL16 handle )
842 TRACE(toolhelp, "%04x\n", handle );
843 if (!handle) return 0;
844 #ifdef CONFIG_IPC
845 if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
846 #endif
847 if (!VALID_HANDLE(handle)) {
848 WARN(global,"Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
849 return 0;
851 if (!(handle & 7))
853 WARN(global, "Program attempted invalid selector conversion\n" );
854 return handle - 1;
856 return handle | 7;
860 /***********************************************************************
861 * GlobalFirst (TOOLHELP.51)
863 BOOL16 WINAPI GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
865 if (wFlags == GLOBAL_LRU) return FALSE;
866 pGlobal->dwNext = 0;
867 return GlobalNext( pGlobal, wFlags );
871 /***********************************************************************
872 * GlobalNext (TOOLHELP.52)
874 BOOL16 WINAPI GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
876 GLOBALARENA *pArena;
878 if (pGlobal->dwNext >= globalArenaSize) return FALSE;
879 pArena = pGlobalArena + pGlobal->dwNext;
880 if (wFlags == GLOBAL_FREE) /* only free blocks */
882 int i;
883 for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
884 if (pArena->size == 0) break; /* block is free */
885 if (i >= globalArenaSize) return FALSE;
886 pGlobal->dwNext = i;
889 pGlobal->dwAddress = pArena->base;
890 pGlobal->dwBlockSize = pArena->size;
891 pGlobal->hBlock = pArena->handle;
892 pGlobal->wcLock = pArena->lockCount;
893 pGlobal->wcPageLock = pArena->pageLockCount;
894 pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
895 pGlobal->wHeapPresent = FALSE;
896 pGlobal->hOwner = pArena->hOwner;
897 pGlobal->wType = GT_UNKNOWN;
898 pGlobal->wData = 0;
899 pGlobal->dwNext++;
900 return TRUE;
904 /***********************************************************************
905 * GlobalInfo (TOOLHELP.53)
907 BOOL16 WINAPI GlobalInfo( GLOBALINFO *pInfo )
909 int i;
910 GLOBALARENA *pArena;
912 pInfo->wcItems = globalArenaSize;
913 pInfo->wcItemsFree = 0;
914 pInfo->wcItemsLRU = 0;
915 for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
916 if (pArena->size == 0) pInfo->wcItemsFree++;
917 return TRUE;
921 /***********************************************************************
922 * GlobalEntryHandle (TOOLHELP.54)
924 BOOL16 WINAPI GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
926 GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
928 pGlobal->dwAddress = pArena->base;
929 pGlobal->dwBlockSize = pArena->size;
930 pGlobal->hBlock = pArena->handle;
931 pGlobal->wcLock = pArena->lockCount;
932 pGlobal->wcPageLock = pArena->pageLockCount;
933 pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
934 pGlobal->wHeapPresent = FALSE;
935 pGlobal->hOwner = pArena->hOwner;
936 pGlobal->wType = GT_UNKNOWN;
937 pGlobal->wData = 0;
938 pGlobal->dwNext++;
939 return TRUE;
943 /***********************************************************************
944 * GlobalEntryModule (TOOLHELP.55)
946 BOOL16 WINAPI GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule,
947 WORD wSeg )
949 return FALSE;
953 /***********************************************************************
954 * MemManInfo (TOOLHELP.72)
956 BOOL16 WINAPI MemManInfo( MEMMANINFO *info )
958 MEMORYSTATUS status;
961 * Not unsurprisingly although the documention says you
962 * _must_ provide the size in the dwSize field, this function
963 * (under Windows) always fills the structure and returns true.
965 GlobalMemoryStatus( &status );
966 info->wPageSize = VIRTUAL_GetPageSize();
967 info->dwLargestFreeBlock = status.dwAvailVirtual;
968 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
969 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
970 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
971 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
972 info->dwFreePages = info->dwMaxPagesAvailable;
973 info->dwTotalPages = info->dwTotalLinearSpace;
974 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
975 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
976 return TRUE;
979 /***********************************************************************
980 * GetFreeMemInfo (KERNEL.316)
982 DWORD WINAPI GetFreeMemInfo(void)
984 MEMMANINFO info;
985 MemManInfo( &info );
986 return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
990 * Win32 Global heap functions (GlobalXXX).
991 * These functions included in Win32 for compatibility with 16 bit Windows
992 * Especially the moveable blocks and handles are oldish.
993 * But the ability to directly allocate memory with GPTR and LPTR is widely
994 * used.
996 * The handle stuff looks horrible, but it's implemented almost like Win95
997 * does it.
1001 #define MAGIC_GLOBAL_USED 0x5342
1002 #define GLOBAL_LOCK_MAX 0xFF
1003 #define HANDLE_TO_INTERN(h) ((PGLOBAL32_INTERN)(((char *)(h))-2))
1004 #define INTERN_TO_HANDLE(i) ((HGLOBAL32) &((i)->Pointer))
1005 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL32 *)(p))-1))
1006 #define ISHANDLE(h) (((DWORD)(h)&2)!=0)
1007 #define ISPOINTER(h) (((DWORD)(h)&2)==0)
1009 typedef struct __GLOBAL32_INTERN
1011 WORD Magic;
1012 LPVOID Pointer WINE_PACKED;
1013 BYTE Flags;
1014 BYTE LockCount;
1015 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
1018 /***********************************************************************
1019 * GlobalAlloc32 (KERNEL32.315)
1020 * RETURNS
1021 * Handle: Success
1022 * NULL: Failure
1024 HGLOBAL32 WINAPI GlobalAlloc32(
1025 UINT32 flags, /* [in] Object allocation attributes */
1026 DWORD size /* [in] Number of bytes to allocate */
1028 PGLOBAL32_INTERN pintern;
1029 DWORD hpflags;
1030 LPVOID palloc;
1032 if(flags&GMEM_ZEROINIT)
1033 hpflags=HEAP_ZERO_MEMORY;
1034 else
1035 hpflags=0;
1037 if((flags & GMEM_MOVEABLE)==0) /* POINTER */
1039 palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
1040 return (HGLOBAL32) palloc;
1042 else /* HANDLE */
1044 /* HeapLock(GetProcessHeap()); */
1046 pintern=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
1047 if(size)
1049 palloc=HeapAlloc(GetProcessHeap(), hpflags, size+sizeof(HGLOBAL32));
1050 *(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
1051 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1053 else
1054 pintern->Pointer=NULL;
1055 pintern->Magic=MAGIC_GLOBAL_USED;
1056 pintern->Flags=flags>>8;
1057 pintern->LockCount=0;
1059 /* HeapUnlock(GetProcessHeap()); */
1061 return INTERN_TO_HANDLE(pintern);
1066 /***********************************************************************
1067 * GlobalLock32 (KERNEL32.326)
1068 * RETURNS
1069 * Pointer to first byte of block
1070 * NULL: Failure
1072 LPVOID WINAPI GlobalLock32(
1073 HGLOBAL32 hmem /* [in] Handle of global memory object */
1075 PGLOBAL32_INTERN pintern;
1076 LPVOID palloc;
1078 if(ISPOINTER(hmem))
1079 return (LPVOID) hmem;
1081 /* HeapLock(GetProcessHeap()); */
1083 pintern=HANDLE_TO_INTERN(hmem);
1084 if(pintern->Magic==MAGIC_GLOBAL_USED)
1086 if(pintern->LockCount<GLOBAL_LOCK_MAX)
1087 pintern->LockCount++;
1088 palloc=pintern->Pointer;
1090 else
1092 WARN(global, "invalid handle\n");
1093 palloc=(LPVOID) NULL;
1095 /* HeapUnlock(GetProcessHeap()); */;
1096 return palloc;
1100 /***********************************************************************
1101 * GlobalUnlock32 (KERNEL32.332)
1102 * RETURNS
1103 * TRUE: Object is still locked
1104 * FALSE: Object is unlocked
1106 BOOL32 WINAPI GlobalUnlock32(
1107 HGLOBAL32 hmem /* [in] Handle of global memory object */
1109 PGLOBAL32_INTERN pintern;
1110 BOOL32 locked;
1112 if(ISPOINTER(hmem))
1113 return FALSE;
1115 /* HeapLock(GetProcessHeap()); */
1116 pintern=HANDLE_TO_INTERN(hmem);
1118 if(pintern->Magic==MAGIC_GLOBAL_USED)
1120 if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
1121 pintern->LockCount--;
1123 locked=(pintern->LockCount==0) ? FALSE : TRUE;
1125 else
1127 WARN(global, "invalid handle\n");
1128 locked=FALSE;
1130 /* HeapUnlock(GetProcessHeap()); */
1131 return locked;
1135 /***********************************************************************
1136 * GlobalHandle32 (KERNEL32.325)
1137 * Returns the handle associated with the specified pointer.
1139 * NOTES
1140 * Since there in only one goto, can it be removed and the return
1141 * be put 'inline'?
1143 * RETURNS
1144 * Handle: Success
1145 * NULL: Failure
1147 HGLOBAL32 WINAPI GlobalHandle32(
1148 LPCVOID pmem /* [in] Pointer to global memory block */
1150 HGLOBAL32 handle;
1152 if (!HEAP_IsInsideHeap( GetProcessHeap(), 0, pmem )) goto error;
1153 handle = POINTER_TO_HANDLE(pmem);
1154 if (HEAP_IsInsideHeap( GetProcessHeap(), 0, (LPCVOID)handle ))
1156 if (HANDLE_TO_INTERN(handle)->Magic == MAGIC_GLOBAL_USED)
1157 return handle; /* valid moveable block */
1159 /* maybe FIXED block */
1160 if (HeapValidate( GetProcessHeap(), 0, pmem ))
1161 return (HGLOBAL32)pmem; /* valid fixed block */
1163 error:
1164 SetLastError( ERROR_INVALID_HANDLE );
1165 return 0;
1169 /***********************************************************************
1170 * GlobalReAlloc32 (KERNEL32.328)
1171 * RETURNS
1172 * Handle: Success
1173 * NULL: Failure
1175 HGLOBAL32 WINAPI GlobalReAlloc32(
1176 HGLOBAL32 hmem, /* [in] Handle of global memory object */
1177 DWORD size, /* [in] New size of block */
1178 UINT32 flags /* [in] How to reallocate object */
1180 LPVOID palloc;
1181 HGLOBAL32 hnew;
1182 PGLOBAL32_INTERN pintern;
1184 hnew = 0;
1185 /* HeapLock(GetProcessHeap()); */
1186 if(flags & GMEM_MODIFY) /* modify flags */
1188 if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
1190 /* make a fixed block moveable
1191 * actually only NT is able to do this. But it's soo simple
1193 if (hmem == 0)
1195 ERR(global, "GlobalReAlloc32 with null handle!\n");
1196 SetLastError( ERROR_INVALID_ACCESS_TO_MEM );
1197 return 0;
1199 size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
1200 hnew=GlobalAlloc32( flags, size);
1201 palloc=GlobalLock32(hnew);
1202 memcpy(palloc, (LPVOID) hmem, size);
1203 GlobalUnlock32(hnew);
1204 GlobalFree32(hmem);
1206 else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
1208 /* change the flags to make our block "discardable" */
1209 pintern=HANDLE_TO_INTERN(hmem);
1210 pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
1211 hnew=hmem;
1213 else
1215 SetLastError(ERROR_INVALID_PARAMETER);
1216 hnew = 0;
1219 else
1221 if(ISPOINTER(hmem))
1223 /* reallocate fixed memory */
1224 hnew=(HGLOBAL32)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size);
1226 else
1228 /* reallocate a moveable block */
1229 pintern=HANDLE_TO_INTERN(hmem);
1230 if(pintern->LockCount>1) {
1231 ERR(global,"handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
1232 SetLastError(ERROR_INVALID_HANDLE);
1233 } else if(size!=0)
1235 hnew=hmem;
1236 if(pintern->Pointer)
1238 palloc=HeapReAlloc(GetProcessHeap(), 0,
1239 pintern->Pointer-sizeof(HGLOBAL32),
1240 size+sizeof(HGLOBAL32) );
1241 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1243 else
1245 palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
1246 *(HGLOBAL32 *)palloc=hmem;
1247 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1250 else
1252 if(pintern->Pointer)
1254 HeapFree(GetProcessHeap(), 0, pintern->Pointer-sizeof(HGLOBAL32));
1255 pintern->Pointer=NULL;
1260 /* HeapUnlock(GetProcessHeap()); */
1261 return hnew;
1265 /***********************************************************************
1266 * GlobalFree32 (KERNEL32.322)
1267 * RETURNS
1268 * NULL: Success
1269 * Handle: Failure
1271 HGLOBAL32 WINAPI GlobalFree32(
1272 HGLOBAL32 hmem /* [in] Handle of global memory object */
1274 PGLOBAL32_INTERN pintern;
1275 HGLOBAL32 hreturned = 0;
1277 if(ISPOINTER(hmem)) /* POINTER */
1279 if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
1281 else /* HANDLE */
1283 /* HeapLock(GetProcessHeap()); */
1284 pintern=HANDLE_TO_INTERN(hmem);
1286 if(pintern->Magic==MAGIC_GLOBAL_USED)
1288 if(pintern->LockCount!=0)
1289 SetLastError(ERROR_INVALID_HANDLE);
1290 if(pintern->Pointer)
1291 if(!HeapFree(GetProcessHeap(), 0,
1292 (char *)(pintern->Pointer)-sizeof(HGLOBAL32)))
1293 hreturned=hmem;
1294 if(!HeapFree(GetProcessHeap(), 0, pintern))
1295 hreturned=hmem;
1297 /* HeapUnlock(GetProcessHeap()); */
1299 return hreturned;
1303 /***********************************************************************
1304 * GlobalSize32 (KERNEL32.329)
1305 * RETURNS
1306 * Size in bytes of the global memory object
1307 * 0: Failure
1309 DWORD WINAPI GlobalSize32(
1310 HGLOBAL32 hmem /* [in] Handle of global memory object */
1312 DWORD retval;
1313 PGLOBAL32_INTERN pintern;
1315 if(ISPOINTER(hmem))
1317 retval=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
1319 else
1321 /* HeapLock(GetProcessHeap()); */
1322 pintern=HANDLE_TO_INTERN(hmem);
1324 if(pintern->Magic==MAGIC_GLOBAL_USED)
1326 retval=HeapSize(GetProcessHeap(), 0,
1327 (char *)(pintern->Pointer)-sizeof(HGLOBAL32))-4;
1329 else
1331 WARN(global, "invalid handle\n");
1332 retval=0;
1334 /* HeapUnlock(GetProcessHeap()); */
1336 return retval;
1340 /***********************************************************************
1341 * GlobalWire32 (KERNEL32.333)
1343 LPVOID WINAPI GlobalWire32(HGLOBAL32 hmem)
1345 return GlobalLock32( hmem );
1349 /***********************************************************************
1350 * GlobalUnWire32 (KERNEL32.330)
1352 BOOL32 WINAPI GlobalUnWire32(HGLOBAL32 hmem)
1354 return GlobalUnlock32( hmem);
1358 /***********************************************************************
1359 * GlobalFix32 (KERNEL32.320)
1361 VOID WINAPI GlobalFix32(HGLOBAL32 hmem)
1363 GlobalLock32( hmem );
1367 /***********************************************************************
1368 * GlobalUnfix32 (KERNEL32.331)
1370 VOID WINAPI GlobalUnfix32(HGLOBAL32 hmem)
1372 GlobalUnlock32( hmem);
1376 /***********************************************************************
1377 * GlobalFlags32 (KERNEL32.321)
1378 * Returns information about the specified global memory object
1380 * NOTES
1381 * Should this return GMEM_INVALID_HANDLE on invalid handle?
1383 * RETURNS
1384 * Value specifying allocation flags and lock count
1385 * GMEM_INVALID_HANDLE: Failure
1387 UINT32 WINAPI GlobalFlags32(
1388 HGLOBAL32 hmem /* [in] Handle to global memory object */
1390 DWORD retval;
1391 PGLOBAL32_INTERN pintern;
1393 if(ISPOINTER(hmem))
1395 retval=0;
1397 else
1399 /* HeapLock(GetProcessHeap()); */
1400 pintern=HANDLE_TO_INTERN(hmem);
1401 if(pintern->Magic==MAGIC_GLOBAL_USED)
1403 retval=pintern->LockCount + (pintern->Flags<<8);
1404 if(pintern->Pointer==0)
1405 retval|= GMEM_DISCARDED;
1407 else
1409 WARN(global,"Invalid handle: %04x", hmem);
1410 retval=0;
1412 /* HeapUnlock(GetProcessHeap()); */
1414 return retval;
1418 /***********************************************************************
1419 * GlobalCompact32 (KERNEL32.316)
1421 DWORD WINAPI GlobalCompact32( DWORD minfree )
1423 return 0; /* GlobalCompact does nothing in Win32 */
1427 /***********************************************************************
1428 * GlobalMemoryStatus (KERNEL32.327)
1429 * RETURNS
1430 * None
1432 VOID WINAPI GlobalMemoryStatus(
1433 LPMEMORYSTATUS lpmem
1435 #ifdef linux
1436 FILE *f = fopen( "/proc/meminfo", "r" );
1437 if (f)
1439 char buffer[256];
1440 int total, used, free;
1442 lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1443 lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1444 while (fgets( buffer, sizeof(buffer), f ))
1446 /* old style /proc/meminfo ... */
1447 if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
1449 lpmem->dwTotalPhys += total;
1450 lpmem->dwAvailPhys += free;
1452 if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1454 lpmem->dwTotalPageFile += total;
1455 lpmem->dwAvailPageFile += free;
1458 /* new style /proc/meminfo ... */
1459 if (sscanf(buffer, "MemTotal: %d", &total))
1460 lpmem->dwTotalPhys = total*1024;
1461 if (sscanf(buffer, "MemFree: %d", &free))
1462 lpmem->dwAvailPhys = free*1024;
1463 if (sscanf(buffer, "SwapTotal: %d", &total))
1464 lpmem->dwTotalPageFile = total*1024;
1465 if (sscanf(buffer, "SwapFree: %d", &free))
1466 lpmem->dwAvailPageFile = free*1024;
1468 fclose( f );
1470 if (lpmem->dwTotalPhys)
1472 lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1473 lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1474 lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
1475 / (lpmem->dwTotalVirtual / 100);
1476 return;
1479 #endif
1480 /* FIXME: should do something for other systems */
1481 lpmem->dwMemoryLoad = 0;
1482 lpmem->dwTotalPhys = 16*1024*1024;
1483 lpmem->dwAvailPhys = 16*1024*1024;
1484 lpmem->dwTotalPageFile = 16*1024*1024;
1485 lpmem->dwAvailPageFile = 16*1024*1024;
1486 lpmem->dwTotalVirtual = 32*1024*1024;
1487 lpmem->dwAvailVirtual = 32*1024*1024;
1491 /**********************************************************************
1492 * WOWGlobalAllocLock (KERNEL32.62)
1494 * Combined GlobalAlloc and GlobalLock.
1496 SEGPTR WINAPI WOWGlobalAllocLock16(DWORD flags,DWORD cb,HGLOBAL16 *hmem)
1498 HGLOBAL16 xhmem;
1499 xhmem = GlobalAlloc16(flags,cb);
1500 if (hmem) *hmem = xhmem;
1501 return WIN16_GlobalLock16(xhmem);
1505 /**********************************************************************
1506 * WOWGlobalUnlockFree (KERNEL32.64)
1508 * Combined GlobalUnlock and GlobalFree.
1510 WORD WINAPI WOWGlobalUnlockFree16(DWORD vpmem) {
1511 if (!GlobalUnlock16(HIWORD(vpmem)))
1512 return 0;
1513 return GlobalFree16(HIWORD(vpmem));