2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
16 #include "selectors.h"
19 #include "stackframe.h"
24 /* Global arena block */
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 */
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 */
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 /***********************************************************************
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
);
81 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
82 if (pGlobalArena
[i
].size
!=0 && (pGlobalArena
[i
].handle
& 0x8000)){
84 DUMP("0x%08x, ",pGlobalArena
[i
].handle
);
92 /***********************************************************************
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
,
105 /* Allocate the selector(s) */
107 sel
= SELECTOR_AllocBlock( ptr
, size
,
108 isCode
? SEGMENT_CODE
: SEGMENT_DATA
,
109 is32Bit
, isReadOnly
);
112 selcount
= (size
+ 0xffff) / 0x10000;
114 if (!(pArena
= GLOBAL_GetArena( sel
, selcount
)))
116 SELECTOR_FreeBlock( sel
, selcount
);
120 /* Fill the arena block */
122 pArena
->base
= (DWORD
)ptr
;
123 pArena
->size
= GET_SEL_LIMIT(sel
) + 1;
126 if (flags
& GMEM_DDESHARE
)
128 pArena
->handle
= shmdata
->handle
;
129 pArena
->shmid
= shmdata
->shmid
;
134 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
138 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
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 /***********************************************************************
158 * Free a block allocated by GLOBAL_CreateBlock, without touching
159 * the associated linear memory range.
161 BOOL16
GLOBAL_FreeBlock( HGLOBAL16 handle
)
166 if (!handle
) return TRUE
;
167 sel
= GlobalHandleToSel( handle
);
168 if (!VALID_HANDLE(sel
))
170 pArena
= GET_ARENA_PTR(sel
);
171 SELECTOR_FreeBlock( sel
, (pArena
->size
+ 0xffff) / 0x10000 );
172 memset( pArena
, 0, sizeof(GLOBALARENA
) );
177 /***********************************************************************
180 * Implementation of GlobalAlloc16()
182 HGLOBAL16
GLOBAL_Alloc( UINT16 flags
, DWORD size
, HGLOBAL16 hOwner
,
183 BOOL16 isCode
, BOOL16 is32Bit
, BOOL16 isReadOnly
)
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
);
198 if (size
>= GLOBAL_MAX_ALLOC_SIZE
- 0x1f) return 0;
199 size
= (size
+ 0x1f) & ~0x1f;
201 /* Allocate the linear memory */
204 if (flags
& GMEM_DDESHARE
)
205 ptr
= DDE_malloc(flags
, size
, &shmdata
);
207 #endif /* CONFIG_IPC */
209 ptr
= HeapAlloc( SystemHeap
, 0, size
);
211 /* FIXME: free discardable blocks and try again? */
214 /* Allocate the selector(s) */
216 handle
= GLOBAL_CreateBlock( flags
, ptr
, size
, hOwner
,
217 isCode
, is32Bit
, isReadOnly
, &shmdata
);
220 HeapFree( SystemHeap
, 0, ptr
);
224 if (flags
& GMEM_ZEROINIT
) memset( ptr
, 0, size
);
230 /***********************************************************************
233 * Find the arena for a given handle
234 * (when handle is not serial - e.g. DDE)
236 static GLOBALARENA
*GLOBAL_FindArena( HGLOBAL16 handle
)
239 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
240 if (pGlobalArena
[i
].size
!=0 && pGlobalArena
[i
].handle
== handle
)
241 return ( &pGlobalArena
[i
] );
247 /***********************************************************************
248 * DDE_GlobalHandleToSel
251 WORD
DDE_GlobalHandleToSel( HGLOBAL16 handle
)
256 pArena
= GLOBAL_FindArena(handle
);
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)
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)
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 */
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;
312 if (flags
& GMEM_DDESHARE
|| is_dde_handle(handle
))
314 FIXME(global
, "shared memory reallocating unimplemented\n");
317 #endif /* CONFIG_IPC */
319 if (!VALID_HANDLE(handle
)) {
320 WARN(global
, "Invalid handle 0x%04x!\n", handle
);
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
);
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 );
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
;
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
);
369 SELECTOR_FreeBlock( sel
, (oldsize
+ 0xffff) / 0x10000 );
370 memset( pArena
, 0, sizeof(GLOBALARENA
) );
374 /* Reallocate the selector(s) */
376 sel
= SELECTOR_ReallocBlock( sel
, ptr
, size
, SEGMENT_DATA
, 0, 0 );
379 HeapFree( SystemHeap
, 0, ptr
);
380 memset( pArena
, 0, sizeof(GLOBALARENA
) );
383 selcount
= (size
+ 0xffff) / 0x10000;
385 if (!(pNewArena
= GLOBAL_GetArena( sel
, selcount
)))
387 HeapFree( SystemHeap
, 0, ptr
);
388 SELECTOR_FreeBlock( sel
, selcount
);
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)
415 HGLOBAL16 WINAPI
GlobalFree16(
416 HGLOBAL16 handle
/* [in] Handle of global memory object */
420 if (!VALID_HANDLE(handle
)) {
421 WARN(global
,"Invalid handle 0x%04x passed to GlobalFree16!\n",handle
);
424 ptr
= (void *)GET_ARENA_PTR(handle
)->base
;
426 TRACE(global
, "%04x\n", handle
);
427 if (!GLOBAL_FreeBlock( handle
)) return handle
; /* failed */
429 if (is_dde_handle(handle
)) return DDE_GlobalFree(handle
);
430 #endif /* CONFIG_IPC */
431 if (ptr
) HeapFree( SystemHeap
, 0, ptr
);
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
)) );
447 if (handle
== (HGLOBAL16
)-1) handle
= CURRENT_DS
;
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
);
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 */
467 /***********************************************************************
468 * GlobalLock16 (KERNEL.18)
470 * This is the GlobalLock16() function used by 32-bit code.
473 * Pointer to first byte of memory block
476 LPVOID WINAPI
GlobalLock16(
477 HGLOBAL16 handle
/* [in] Handle of global memory object */
479 if (!handle
) return 0;
480 if (!VALID_HANDLE(handle
))
482 GET_ARENA_PTR(handle
)->lockCount
++;
484 if (is_dde_handle(handle
)) return DDE_AttachHandle(handle
, NULL
);
486 return (LPVOID
)GET_ARENA_PTR(handle
)->base
;
490 /***********************************************************************
491 * GlobalUnlock16 (KERNEL.19)
493 * Should the return values be cast to booleans?
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
);
507 TRACE(global
, "%04x\n", handle
);
508 if (pArena
->lockCount
) pArena
->lockCount
--;
509 return pArena
->lockCount
;
513 /***********************************************************************
514 * GlobalSize16 (KERNEL.20)
516 * Size in bytes of object
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
))
526 return GET_ARENA_PTR(handle
)->size
;
530 /***********************************************************************
531 * GlobalHandle16 (KERNEL.21)
533 * Why is GlobalHandleToSel used here with the sel as input?
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
);
547 return MAKELONG( GET_ARENA_PTR(sel
)->handle
, GlobalHandleToSel(sel
) );
550 /***********************************************************************
551 * GlobalHandleNoRIP (KERNEL.159)
553 DWORD WINAPI
GlobalHandleNoRIP( WORD sel
)
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
) );
564 /***********************************************************************
565 * GlobalFlags16 (KERNEL.22)
567 * Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
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 */
579 TRACE(global
, "%04x\n", handle
);
580 if (!VALID_HANDLE(handle
)) {
581 WARN(global
,"Invalid handle 0x%04x passed to GlobalFlags16!\n",handle
);
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
);
602 GET_ARENA_PTR(handle
)->lockCount
++;
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
);
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
)
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
;
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
;
699 /***********************************************************************
700 * GetFreeSpace16 (KERNEL.169)
702 DWORD WINAPI
GetFreeSpace16( UINT16 wFlags
)
705 GlobalMemoryStatus( &ms
);
706 return ms
.dwAvailVirtual
;
709 /***********************************************************************
710 * GlobalDOSAlloc (KERNEL.184)
712 * Address (HW=Paragraph segment; LW=Selector)
714 DWORD WINAPI
GlobalDOSAlloc(
715 DWORD size
/* [in] Number of bytes to be allocated */
718 LPVOID lpBlock
= DOSMEM_GetBlock( 0, size
, &uParagraph
);
722 HMODULE16 hModule
= GetModuleHandle16("KERNEL");
725 wSelector
= GLOBAL_CreateBlock(GMEM_FIXED
, lpBlock
, size
,
726 hModule
, 0, 0, 0, NULL
);
727 return MAKELONG(wSelector
,uParagraph
);
733 /***********************************************************************
734 * GlobalDOSFree (KERNEL.185)
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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;
845 if (is_dde_handle(handle
)) return DDE_GlobalHandleToSel(handle
);
847 if (!VALID_HANDLE(handle
)) {
848 WARN(global
,"Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle
);
853 WARN(global
, "Program attempted invalid selector conversion\n" );
860 /***********************************************************************
861 * GlobalFirst (TOOLHELP.51)
863 BOOL16 WINAPI
GlobalFirst( GLOBALENTRY
*pGlobal
, WORD wFlags
)
865 if (wFlags
== GLOBAL_LRU
) return FALSE
;
867 return GlobalNext( pGlobal
, wFlags
);
871 /***********************************************************************
872 * GlobalNext (TOOLHELP.52)
874 BOOL16 WINAPI
GlobalNext( GLOBALENTRY
*pGlobal
, WORD wFlags
)
878 if (pGlobal
->dwNext
>= globalArenaSize
) return FALSE
;
879 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
880 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
883 for (i
= pGlobal
->dwNext
; i
< globalArenaSize
; i
++, pArena
++)
884 if (pArena
->size
== 0) break; /* block is free */
885 if (i
>= globalArenaSize
) return FALSE
;
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
;
904 /***********************************************************************
905 * GlobalInfo (TOOLHELP.53)
907 BOOL16 WINAPI
GlobalInfo( GLOBALINFO
*pInfo
)
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
++;
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
;
943 /***********************************************************************
944 * GlobalEntryModule (TOOLHELP.55)
946 BOOL16 WINAPI
GlobalEntryModule( GLOBALENTRY
*pGlobal
, HMODULE16 hModule
,
953 /***********************************************************************
954 * MemManInfo (TOOLHELP.72)
956 BOOL16 WINAPI
MemManInfo( MEMMANINFO
*info
)
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
;
979 /***********************************************************************
980 * GetFreeMemInfo (KERNEL.316)
982 DWORD WINAPI
GetFreeMemInfo(void)
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
996 * The handle stuff looks horrible, but it's implemented almost like Win95
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
1012 LPVOID Pointer WINE_PACKED
;
1015 } GLOBAL32_INTERN
, *PGLOBAL32_INTERN
;
1018 /***********************************************************************
1019 * GlobalAlloc32 (KERNEL32.315)
1024 HGLOBAL32 WINAPI
GlobalAlloc32(
1025 UINT32 flags
, /* [in] Object allocation attributes */
1026 DWORD size
/* [in] Number of bytes to allocate */
1028 PGLOBAL32_INTERN pintern
;
1032 if(flags
&GMEM_ZEROINIT
)
1033 hpflags
=HEAP_ZERO_MEMORY
;
1037 if((flags
& GMEM_MOVEABLE
)==0) /* POINTER */
1039 palloc
=HeapAlloc(GetProcessHeap(), hpflags
, size
);
1040 return (HGLOBAL32
) palloc
;
1044 /* HeapLock(GetProcessHeap()); */
1046 pintern
=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN
));
1049 palloc
=HeapAlloc(GetProcessHeap(), hpflags
, size
+sizeof(HGLOBAL32
));
1050 *(HGLOBAL32
*)palloc
=INTERN_TO_HANDLE(pintern
);
1051 pintern
->Pointer
=palloc
+sizeof(HGLOBAL32
);
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)
1069 * Pointer to first byte of block
1072 LPVOID WINAPI
GlobalLock32(
1073 HGLOBAL32 hmem
/* [in] Handle of global memory object */
1075 PGLOBAL32_INTERN pintern
;
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
;
1092 WARN(global
, "invalid handle\n");
1093 palloc
=(LPVOID
) NULL
;
1095 /* HeapUnlock(GetProcessHeap()); */;
1100 /***********************************************************************
1101 * GlobalUnlock32 (KERNEL32.332)
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
;
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
;
1127 WARN(global
, "invalid handle\n");
1130 /* HeapUnlock(GetProcessHeap()); */
1135 /***********************************************************************
1136 * GlobalHandle32 (KERNEL32.325)
1137 * Returns the handle associated with the specified pointer.
1140 * Since there in only one goto, can it be removed and the return
1147 HGLOBAL32 WINAPI
GlobalHandle32(
1148 LPCVOID pmem
/* [in] Pointer to global memory block */
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 */
1164 SetLastError( ERROR_INVALID_HANDLE
);
1169 /***********************************************************************
1170 * GlobalReAlloc32 (KERNEL32.328)
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 */
1182 PGLOBAL32_INTERN pintern
;
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
1195 ERR(global
, "GlobalReAlloc32 with null handle!\n");
1196 SetLastError( ERROR_INVALID_ACCESS_TO_MEM
);
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
);
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);
1215 SetLastError(ERROR_INVALID_PARAMETER
);
1223 /* reallocate fixed memory */
1224 hnew
=(HGLOBAL32
)HeapReAlloc(GetProcessHeap(), 0, (LPVOID
) hmem
, size
);
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
);
1236 if(pintern
->Pointer
)
1238 palloc
=HeapReAlloc(GetProcessHeap(), 0,
1239 pintern
->Pointer
-sizeof(HGLOBAL32
),
1240 size
+sizeof(HGLOBAL32
) );
1241 pintern
->Pointer
=palloc
+sizeof(HGLOBAL32
);
1245 palloc
=HeapAlloc(GetProcessHeap(), 0, size
+sizeof(HGLOBAL32
));
1246 *(HGLOBAL32
*)palloc
=hmem
;
1247 pintern
->Pointer
=palloc
+sizeof(HGLOBAL32
);
1252 if(pintern
->Pointer
)
1254 HeapFree(GetProcessHeap(), 0, pintern
->Pointer
-sizeof(HGLOBAL32
));
1255 pintern
->Pointer
=NULL
;
1260 /* HeapUnlock(GetProcessHeap()); */
1265 /***********************************************************************
1266 * GlobalFree32 (KERNEL32.322)
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;
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
)))
1294 if(!HeapFree(GetProcessHeap(), 0, pintern
))
1297 /* HeapUnlock(GetProcessHeap()); */
1303 /***********************************************************************
1304 * GlobalSize32 (KERNEL32.329)
1306 * Size in bytes of the global memory object
1309 DWORD WINAPI
GlobalSize32(
1310 HGLOBAL32 hmem
/* [in] Handle of global memory object */
1313 PGLOBAL32_INTERN pintern
;
1317 retval
=HeapSize(GetProcessHeap(), 0, (LPVOID
) hmem
);
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;
1331 WARN(global
, "invalid handle\n");
1334 /* HeapUnlock(GetProcessHeap()); */
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
1381 * Should this return GMEM_INVALID_HANDLE on invalid handle?
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 */
1391 PGLOBAL32_INTERN pintern
;
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
;
1409 WARN(global
,"Invalid handle: %04x", hmem
);
1412 /* HeapUnlock(GetProcessHeap()); */
1418 /***********************************************************************
1419 * GlobalCompact32 (KERNEL32.316)
1421 DWORD WINAPI
GlobalCompact32( DWORD minfree
)
1423 return 0; /* GlobalCompact does nothing in Win32 */
1427 /***********************************************************************
1428 * GlobalMemoryStatus (KERNEL32.327)
1432 VOID WINAPI
GlobalMemoryStatus(
1433 LPMEMORYSTATUS lpmem
1436 FILE *f
= fopen( "/proc/meminfo", "r" );
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;
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);
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
)
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
)))
1513 return GlobalFree16(HIWORD(vpmem
));