diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index 8e0f8d437c3..9360bf69e86 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -236,78 +236,6 @@ typedef struct __GLOBAL32_INTERN #include "poppack.h" -/*********************************************************************** - * GlobalAlloc (KERNEL32.@) - * - * Allocate a global memory object. - * - * RETURNS - * Handle: Success - * NULL: Failure - */ -HGLOBAL WINAPI GlobalAlloc( - UINT flags, /* [in] Object allocation attributes */ - SIZE_T size /* [in] Number of bytes to allocate */ -) { - PGLOBAL32_INTERN pintern; - DWORD hpflags; - LPVOID palloc; - - if(flags&GMEM_ZEROINIT) - hpflags=HEAP_ZERO_MEMORY; - else - hpflags=0; - - if((flags & GMEM_MOVEABLE)==0) /* POINTER */ - { - palloc = HeapAlloc( GetProcessHeap(), hpflags, max( 1, size )); - TRACE( "(flags=%04x) returning %p\n", flags, palloc ); - return palloc; - } - else /* HANDLE */ - { - if (size > INT_MAX-HGLOBAL_STORAGE) - { - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - - pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN)); - if (pintern) - { - /* Mask out obsolete flags */ - flags &= ~(GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NOT_BANKED | GMEM_NOTIFY); - - pintern->Magic = MAGIC_GLOBAL_USED; - pintern->Flags = flags >> 8; - pintern->LockCount = 0; - - if (size) - { - palloc = HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE); - if (!palloc) - { - HeapFree(GetProcessHeap(), 0, pintern); - pintern = NULL; - } - else - { - *(HGLOBAL *)palloc = INTERN_TO_HANDLE(pintern); - pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE; - } - } - else - pintern->Pointer = NULL; - } - - if (!pintern) return 0; - TRACE( "(flags=%04x) returning handle %p pointer %p\n", - flags, INTERN_TO_HANDLE(pintern), pintern->Pointer ); - return INTERN_TO_HANDLE(pintern); - } -} - - /*********************************************************************** * GlobalLock (KERNEL32.@) * @@ -326,40 +254,7 @@ HGLOBAL WINAPI GlobalAlloc( */ LPVOID WINAPI GlobalLock(HGLOBAL hmem) { - PGLOBAL32_INTERN pintern; - LPVOID palloc; - - if (ISPOINTER(hmem)) - return IsBadReadPtr(hmem, 1) ? NULL : hmem; - - RtlLockHeap(GetProcessHeap()); - __TRY - { - pintern = HANDLE_TO_INTERN(hmem); - if (pintern->Magic == MAGIC_GLOBAL_USED) - { - palloc = pintern->Pointer; - if (!pintern->Pointer) - SetLastError(ERROR_DISCARDED); - else if (pintern->LockCount < GMEM_LOCKCOUNT) - pintern->LockCount++; - } - else - { - WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic); - palloc = NULL; - SetLastError(ERROR_INVALID_HANDLE); - } - } - __EXCEPT_PAGE_FAULT - { - WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem); - palloc = NULL; - SetLastError(ERROR_INVALID_HANDLE); - } - __ENDTRY - RtlUnlockHeap(GetProcessHeap()); - return palloc; + return LocalLock( hmem ); } @@ -381,46 +276,8 @@ LPVOID WINAPI GlobalLock(HGLOBAL hmem) */ BOOL WINAPI GlobalUnlock(HGLOBAL hmem) { - PGLOBAL32_INTERN pintern; - BOOL locked; - - if (ISPOINTER(hmem)) return TRUE; - - RtlLockHeap(GetProcessHeap()); - __TRY - { - pintern=HANDLE_TO_INTERN(hmem); - if(pintern->Magic==MAGIC_GLOBAL_USED) - { - if(pintern->LockCount) - { - pintern->LockCount--; - locked = (pintern->LockCount != 0); - if (!locked) SetLastError(NO_ERROR); - } - else - { - WARN("%p not locked\n", hmem); - SetLastError(ERROR_NOT_LOCKED); - locked = FALSE; - } - } - else - { - WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic); - SetLastError(ERROR_INVALID_HANDLE); - locked=FALSE; - } - } - __EXCEPT_PAGE_FAULT - { - WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem); - SetLastError( ERROR_INVALID_PARAMETER ); - locked=FALSE; - } - __ENDTRY - RtlUnlockHeap(GetProcessHeap()); - return locked; + if (ISPOINTER( hmem )) return TRUE; + return LocalUnlock( hmem ); } @@ -495,200 +352,9 @@ HGLOBAL WINAPI GlobalHandle( * Handle: Success * NULL: Failure */ -HGLOBAL WINAPI GlobalReAlloc( - HGLOBAL hmem, /* [in] Handle of global memory object */ - SIZE_T size, /* [in] New size of block */ - UINT flags /* [in] How to reallocate object */ -) { - LPVOID palloc; - HGLOBAL hnew; - PGLOBAL32_INTERN pintern; - DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0; - - hnew = 0; - RtlLockHeap(GetProcessHeap()); - if(flags & GMEM_MODIFY) /* modify flags */ - { - if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE)) - { - /* make a fixed block moveable - * actually only NT is able to do this. But it's soo simple - */ - if (hmem == 0) - { - WARN("GlobalReAlloc with null handle!\n"); - SetLastError( ERROR_NOACCESS ); - hnew = 0; - } - else - { - size = HeapSize(GetProcessHeap(), 0, hmem); - hnew = GlobalAlloc(flags, size); - palloc = GlobalLock(hnew); - memcpy(palloc, hmem, size); - GlobalUnlock(hnew); - GlobalFree(hmem); - } - } - else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE)) - { - /* change the flags to make our block "discardable" */ - pintern=HANDLE_TO_INTERN(hmem); - pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8); - hnew=hmem; - } - else - { - SetLastError(ERROR_INVALID_PARAMETER); - hnew = 0; - } - } - else - { - if(ISPOINTER(hmem)) - { - /* reallocate fixed memory */ - if (!(flags & GMEM_MOVEABLE)) - heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY; - hnew=HeapReAlloc(GetProcessHeap(), heap_flags, hmem, size); - } - else - { - /* reallocate a moveable block */ - pintern=HANDLE_TO_INTERN(hmem); - -#if 0 -/* Apparently Windows doesn't care whether the handle is locked at this point */ -/* See also the same comment in GlobalFree() */ - if(pintern->LockCount>1) { - ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem); - SetLastError(ERROR_INVALID_HANDLE); - } else -#endif - if(size!=0) - { - hnew=hmem; - if(pintern->Pointer) - { - if(size > INT_MAX-HGLOBAL_STORAGE) - { - SetLastError(ERROR_OUTOFMEMORY); - hnew = 0; - } - else if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags, - (char *) pintern->Pointer-HGLOBAL_STORAGE, - size+HGLOBAL_STORAGE)) == NULL) - hnew = 0; /* Block still valid */ - else - pintern->Pointer = (char *)palloc+HGLOBAL_STORAGE; - } - else - { - if(size > INT_MAX-HGLOBAL_STORAGE) - { - SetLastError(ERROR_OUTOFMEMORY); - hnew = 0; - } - else if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE)) - == NULL) - hnew = 0; - else - { - *(HGLOBAL *)palloc = hmem; - pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE; - } - } - } - else - { - if (pintern->LockCount == 0) - { - if(pintern->Pointer) - { - HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE); - pintern->Pointer = NULL; - } - hnew = hmem; - } - else - WARN("not freeing memory associated with locked handle\n"); - } - } - } - RtlUnlockHeap(GetProcessHeap()); - return hnew; -} - - -/*********************************************************************** - * GlobalFree (KERNEL32.@) - * - * Free a global memory object. - * - * PARAMS - * hmem [I] Handle of the global memory object - * - * RETURNS - * Success: NULL - * Failure: The provided handle - * - * NOTES - * When the handle is invalid, last error is set to ERROR_INVALID_HANDLE - * - */ -HGLOBAL WINAPI GlobalFree(HGLOBAL hmem) +HGLOBAL WINAPI GlobalReAlloc( HGLOBAL hmem, SIZE_T size, UINT flags ) { - PGLOBAL32_INTERN pintern; - HGLOBAL hreturned; - - RtlLockHeap(GetProcessHeap()); - __TRY - { - hreturned = 0; - if(ISPOINTER(hmem)) /* POINTER */ - { - if(!HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, hmem)) - { - SetLastError(ERROR_INVALID_HANDLE); - hreturned = hmem; - } - } - else /* HANDLE */ - { - pintern=HANDLE_TO_INTERN(hmem); - - if(pintern->Magic==MAGIC_GLOBAL_USED) - { - pintern->Magic = 0xdead; - - /* WIN98 does not make this test. That is you can free a */ - /* block you have not unlocked. Go figure!! */ - /* if(pintern->LockCount!=0) */ - /* SetLastError(ERROR_INVALID_HANDLE); */ - - if(pintern->Pointer) - if(!HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (char *)(pintern->Pointer)-HGLOBAL_STORAGE)) - hreturned=hmem; - if(!HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pintern)) - hreturned=hmem; - } - else - { - WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic); - SetLastError(ERROR_INVALID_HANDLE); - hreturned = hmem; - } - } - } - __EXCEPT_PAGE_FAULT - { - ERR("invalid handle %p\n", hmem); - SetLastError(ERROR_INVALID_HANDLE); - hreturned = hmem; - } - __ENDTRY - RtlUnlockHeap(GetProcessHeap()); - return hreturned; + return LocalReAlloc( hmem, size, flags ); } @@ -846,33 +512,6 @@ SIZE_T WINAPI GlobalCompact( DWORD minfree ) } -/*********************************************************************** - * LocalAlloc (KERNEL32.@) - * - * Allocate a local memory object. - * - * RETURNS - * Handle: Success - * NULL: Failure - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. - */ -HLOCAL WINAPI LocalAlloc( UINT flags, SIZE_T size ) -{ - /* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */ - if (!(flags & LMEM_MOVEABLE)) - { - DWORD heap_flags = (flags & LMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0; - void *ret = HeapAlloc( GetProcessHeap(), heap_flags, size ); - TRACE( "(flags=%04x) returning %p\n", flags, ret ); - return ret; - } - return GlobalAlloc( flags, size ); -} - - /*********************************************************************** * LocalCompact (KERNEL32.@) */ @@ -902,26 +541,6 @@ UINT WINAPI LocalFlags( } -/*********************************************************************** - * LocalFree (KERNEL32.@) - * - * Free a local memory object. - * - * RETURNS - * NULL: Success - * Handle: Failure - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. - */ -HLOCAL WINAPI LocalFree( - HLOCAL handle /* [in] Handle of memory object */ -) { - return GlobalFree( handle ); -} - - /*********************************************************************** * LocalHandle (KERNEL32.@) * @@ -942,48 +561,6 @@ HLOCAL WINAPI LocalHandle( } -/*********************************************************************** - * LocalLock (KERNEL32.@) - * Locks a local memory object and returns pointer to the first byte - * of the memory block. - * - * RETURNS - * Pointer: Success - * NULL: Failure - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. - */ -LPVOID WINAPI LocalLock( - HLOCAL handle /* [in] Address of local memory object */ -) { - return GlobalLock( handle ); -} - - -/*********************************************************************** - * LocalReAlloc (KERNEL32.@) - * - * Change the size or attributes of a local memory object. - * - * RETURNS - * Handle: Success - * NULL: Failure - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. - */ -HLOCAL WINAPI LocalReAlloc( - HLOCAL handle, /* [in] Handle of memory object */ - SIZE_T size, /* [in] New size of block */ - UINT flags /* [in] How to reallocate object */ -) { - return GlobalReAlloc( handle, size, flags ); -} - - /*********************************************************************** * LocalShrink (KERNEL32.@) */ @@ -1013,32 +590,6 @@ SIZE_T WINAPI LocalSize( } -/*********************************************************************** - * LocalUnlock (KERNEL32.@) - * - * Unlock a local memory object. - * - * RETURNS - * TRUE: Object is still locked - * FALSE: Object is unlocked - * - * NOTES - * Windows memory management does not provide a separate local heap - * and global heap. - */ -BOOL WINAPI LocalUnlock( - HLOCAL handle /* [in] Handle of memory object */ -) -{ - if (ISPOINTER( handle )) - { - SetLastError( ERROR_NOT_LOCKED ); - return FALSE; - } - - return GlobalUnlock( handle ); -} - /*********************************************************************** * GlobalMemoryStatusEx (KERNEL32.@) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 33c97fd16f1..f9d24a7e38d 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -893,14 +893,14 @@ # @ stub GetXStateFeaturesMask @ stdcall GlobalAddAtomA(str) @ stdcall GlobalAddAtomW(wstr) -@ stdcall GlobalAlloc(long long) +@ stdcall -import GlobalAlloc(long long) @ stdcall GlobalCompact(long) @ stdcall GlobalDeleteAtom(long) @ stdcall GlobalFindAtomA(str) @ stdcall GlobalFindAtomW(wstr) @ stdcall GlobalFix(long) @ stdcall GlobalFlags(long) -@ stdcall GlobalFree(long) +@ stdcall -import GlobalFree(long) @ stdcall GlobalGetAtomNameA(long ptr long) @ stdcall GlobalGetAtomNameW(long ptr long) @ stdcall GlobalHandle(ptr) @@ -1050,17 +1050,17 @@ @ stdcall -import LoadResource(long long) # @ stub LoadStringBaseExW # @ stub LoadStringBaseW -@ stdcall LocalAlloc(long long) +@ stdcall -import LocalAlloc(long long) @ stdcall LocalCompact(long) @ stdcall LocalFileTimeToFileTime(ptr ptr) @ stdcall LocalFlags(long) -@ stdcall LocalFree(long) +@ stdcall -import LocalFree(long) @ stdcall LocalHandle(ptr) -@ stdcall LocalLock(long) -@ stdcall LocalReAlloc(long long long) +@ stdcall -import LocalLock(long) +@ stdcall -import LocalReAlloc(long long long) @ stdcall LocalShrink(long long) @ stdcall LocalSize(long) -@ stdcall LocalUnlock(long) +@ stdcall -import LocalUnlock(long) @ stdcall LocaleNameToLCID(wstr long) # @ stub LocateXStateFeature @ stdcall -import LockFile(long long long long long) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index e4125a4c05e..6a137dc69df 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -766,8 +766,8 @@ # @ stub GetWsChanges # @ stub GetWsChangesEx # @ stub GetXStateFeaturesMask -@ stdcall GlobalAlloc(long long) kernel32.GlobalAlloc -@ stdcall GlobalFree(long) kernel32.GlobalFree +@ stdcall GlobalAlloc(long long) +@ stdcall GlobalFree(long) @ stdcall GlobalMemoryStatusEx(ptr) kernel32.GlobalMemoryStatusEx # @ stub GuardCheckLongJumpTarget # @ stub HasPolicyForegroundProcessingCompletedInternal @@ -933,12 +933,12 @@ @ stub LoadStringBaseExW @ stub LoadStringByReference @ stdcall LoadStringW(long long ptr long) -@ stdcall LocalAlloc(long long) kernel32.LocalAlloc +@ stdcall LocalAlloc(long long) @ stdcall LocalFileTimeToFileTime(ptr ptr) kernel32.LocalFileTimeToFileTime -@ stdcall LocalFree(long) kernel32.LocalFree -@ stdcall LocalLock(long) kernel32.LocalLock -@ stdcall LocalReAlloc(long long long) kernel32.LocalReAlloc -@ stdcall LocalUnlock(long) kernel32.LocalUnlock +@ stdcall LocalFree(long) +@ stdcall LocalLock(long) +@ stdcall LocalReAlloc(long long long) +@ stdcall LocalUnlock(long) @ stdcall LocaleNameToLCID(wstr long) kernel32.LocaleNameToLCID # @ stub LocateXStateFeature @ stdcall LockFile(long long long long long) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index aa834a39a92..aee69d4d78a 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ntstatus.h" @@ -36,7 +37,7 @@ #include "wine/exception.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(virtual); +WINE_DEFAULT_DEBUG_CHANNEL(heap); /*********************************************************************** @@ -384,6 +385,354 @@ BOOL WINAPI DECLSPEC_HOTPATCH HeapWalk( HANDLE heap, PROCESS_HEAP_ENTRY *entry ) } +/*********************************************************************** + * Global/local heap functions + ***********************************************************************/ + +#include "pshpack1.h" + +struct local_header +{ + WORD magic; + void *ptr; + BYTE flags; + BYTE lock; +}; + +#include "poppack.h" + +#define MAGIC_LOCAL_USED 0x5342 +/* align the storage needed for the HLOCAL on an 8-byte boundary thus + * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with + * size = 8*k, where k=1,2,3,... allocs exactly the given size. + * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting + * the output jpeg's > 1 MB if not */ +#define HLOCAL_STORAGE (sizeof(HLOCAL) * 2) + +static inline struct local_header *get_header( HLOCAL hmem ) +{ + return (struct local_header *)((char *)hmem - 2); +} + +static inline HLOCAL get_handle( struct local_header *header ) +{ + return &header->ptr; +} + +static inline BOOL is_pointer( HLOCAL hmem ) +{ + return !((ULONG_PTR)hmem & 2); +} + +/*********************************************************************** + * GlobalAlloc (kernelbase.@) + */ +HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalAlloc( UINT flags, SIZE_T size ) +{ + /* mask out obsolete flags */ + flags &= ~(GMEM_NOCOMPACT | GMEM_NOT_BANKED | GMEM_NOTIFY); + + /* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */ + if (!(flags & GMEM_MOVEABLE) && !size) size = 1; + + return LocalAlloc( flags, size ); +} + + +/*********************************************************************** + * GlobalFree (kernelbase.@) + */ +HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL hmem ) +{ + return LocalFree( hmem ); +} + + +/*********************************************************************** + * LocalAlloc (kernelbase.@) + */ +HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) +{ + struct local_header *header; + DWORD heap_flags = 0; + void *ptr; + + if (flags & LMEM_ZEROINIT) heap_flags = HEAP_ZERO_MEMORY; + + if (!(flags & LMEM_MOVEABLE)) /* pointer */ + { + ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ); + TRACE( "(flags=%04x) returning %p\n", flags, ptr ); + return ptr; + } + + if (size > INT_MAX - HLOCAL_STORAGE) + { + SetLastError( ERROR_OUTOFMEMORY ); + return 0; + } + if (!(header = HeapAlloc( GetProcessHeap(), 0, sizeof(*header) ))) return 0; + + header->magic = MAGIC_LOCAL_USED; + header->flags = flags >> 8; + header->lock = 0; + + if (size) + { + if (!(ptr = HeapAlloc(GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE ))) + { + HeapFree( GetProcessHeap(), 0, header ); + return 0; + } + *(HLOCAL *)ptr = get_handle( header ); + header->ptr = (char *)ptr + HLOCAL_STORAGE; + } + else header->ptr = NULL; + + TRACE( "(flags=%04x) returning handle %p pointer %p\n", + flags, get_handle( header ), header->ptr ); + return get_handle( header ); +} + + +/*********************************************************************** + * LocalFree (kernelbase.@) + */ +HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL hmem ) +{ + struct local_header *header; + HLOCAL ret; + + RtlLockHeap( GetProcessHeap() ); + __TRY + { + ret = 0; + if (is_pointer(hmem)) /* POINTER */ + { + if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, hmem )) + { + SetLastError( ERROR_INVALID_HANDLE ); + ret = hmem; + } + } + else /* HANDLE */ + { + header = get_header( hmem ); + if (header->magic == MAGIC_LOCAL_USED) + { + header->magic = 0xdead; + if (header->ptr) + { + if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, + (char *)header->ptr - HLOCAL_STORAGE )) + ret = hmem; + } + if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, header )) ret = hmem; + } + else + { + WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic ); + SetLastError( ERROR_INVALID_HANDLE ); + ret = hmem; + } + } + } + __EXCEPT_PAGE_FAULT + { + WARN( "invalid handle %p\n", hmem ); + SetLastError( ERROR_INVALID_HANDLE ); + ret = hmem; + } + __ENDTRY + RtlUnlockHeap( GetProcessHeap() ); + return ret; +} + + +/*********************************************************************** + * LocalLock (kernelbase.@) + */ +LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL hmem ) +{ + void *ret = NULL; + + if (is_pointer( hmem )) return IsBadReadPtr( hmem, 1 ) ? NULL : hmem; + + RtlLockHeap( GetProcessHeap() ); + __TRY + { + struct local_header *header = get_header( hmem ); + if (header->magic == MAGIC_LOCAL_USED) + { + ret = header->ptr; + if (!header->ptr) SetLastError( ERROR_DISCARDED ); + else if (header->lock < LMEM_LOCKCOUNT) header->lock++; + } + else + { + WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic ); + SetLastError( ERROR_INVALID_HANDLE ); + } + } + __EXCEPT_PAGE_FAULT + { + WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem); + SetLastError( ERROR_INVALID_HANDLE ); + } + __ENDTRY + RtlUnlockHeap( GetProcessHeap() ); + return ret; +} + + +/*********************************************************************** + * LocalReAlloc (kernelbase.@) + */ +HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL hmem, SIZE_T size, UINT flags ) +{ + struct local_header *header; + void *ptr; + HLOCAL ret = 0; + DWORD heap_flags = (flags & LMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0; + + RtlLockHeap( GetProcessHeap() ); + if (flags & LMEM_MODIFY) /* modify flags */ + { + if (is_pointer( hmem ) && (flags & LMEM_MOVEABLE)) + { + /* make a fixed block moveable + * actually only NT is able to do this. But it's soo simple + */ + if (hmem == 0) + { + WARN( "null handle\n"); + SetLastError( ERROR_NOACCESS ); + } + else + { + size = RtlSizeHeap( GetProcessHeap(), 0, hmem ); + ret = LocalAlloc( flags, size ); + ptr = LocalLock( ret ); + memcpy( ptr, hmem, size ); + LocalUnlock( ret ); + LocalFree( hmem ); + } + } + else if (!is_pointer( hmem ) && (flags & LMEM_DISCARDABLE)) + { + /* change the flags to make our block "discardable" */ + header = get_header( hmem ); + header->flags |= LMEM_DISCARDABLE >> 8; + ret = hmem; + } + else SetLastError( ERROR_INVALID_PARAMETER ); + } + else + { + if (is_pointer( hmem )) + { + /* reallocate fixed memory */ + if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY; + ret = HeapReAlloc( GetProcessHeap(), heap_flags, hmem, size ); + } + else + { + /* reallocate a moveable block */ + header = get_header( hmem ); + if (size != 0) + { + if (size <= INT_MAX - HLOCAL_STORAGE) + { + if (header->ptr) + { + if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags, + (char *)header->ptr - HLOCAL_STORAGE, + size + HLOCAL_STORAGE ))) + { + header->ptr = (char *)ptr + HLOCAL_STORAGE; + ret = hmem; + } + } + else + { + if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE ))) + { + *(HLOCAL *)ptr = hmem; + header->ptr = (char *)ptr + HLOCAL_STORAGE; + ret = hmem; + } + } + } + else SetLastError( ERROR_OUTOFMEMORY ); + } + else + { + if (header->lock == 0) + { + if (header->ptr) + { + HeapFree( GetProcessHeap(), 0, (char *)header->ptr - HLOCAL_STORAGE ); + header->ptr = NULL; + } + ret = hmem; + } + else WARN( "not freeing memory associated with locked handle\n" ); + } + } + } + RtlUnlockHeap( GetProcessHeap() ); + return ret; +} + + +/*********************************************************************** + * LocalUnlock (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH LocalUnlock( HLOCAL hmem ) +{ + BOOL ret = FALSE; + + if (is_pointer( hmem )) + { + SetLastError( ERROR_NOT_LOCKED ); + return FALSE; + } + + RtlLockHeap( GetProcessHeap() ); + __TRY + { + struct local_header *header = get_header( hmem ); + if (header->magic == MAGIC_LOCAL_USED) + { + if (header->lock) + { + header->lock--; + ret = (header->lock != 0); + if (!ret) SetLastError( NO_ERROR ); + } + else + { + WARN( "%p not locked\n", hmem ); + SetLastError( ERROR_NOT_LOCKED ); + } + } + else + { + WARN( "invalid handle %p (Magic: 0x%04x)\n", hmem, header->magic ); + SetLastError( ERROR_INVALID_HANDLE ); + } + } + __EXCEPT_PAGE_FAULT + { + WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem); + SetLastError( ERROR_INVALID_PARAMETER ); + } + __ENDTRY + RtlUnlockHeap( GetProcessHeap() ); + return ret; +} + + /*********************************************************************** * Memory resource functions ***********************************************************************/