tests: Don't initialize static variables to 0.
[wine.git] / dlls / kernelbase / memory.c
blob1bce74a6360dd986b58b0c65b0f7aa0602619ac3
1 /*
2 * Win32 memory management functions
4 * Copyright 1997 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <sys/types.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winternl.h"
35 #include "winerror.h"
37 #include "kernelbase.h"
38 #include "wine/exception.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(heap);
42 WINE_DECLARE_DEBUG_CHANNEL(virtual);
45 /***********************************************************************
46 * Virtual memory functions
47 ***********************************************************************/
50 /***********************************************************************
51 * FlushViewOfFile (kernelbase.@)
53 BOOL WINAPI DECLSPEC_HOTPATCH FlushViewOfFile( const void *base, SIZE_T size )
55 NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
57 if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
58 return set_ntstatus( status );
62 /***********************************************************************
63 * GetLargePageMinimum (kernelbase.@)
65 SIZE_T WINAPI GetLargePageMinimum(void)
67 return 2 * 1024 * 1024;
71 /***********************************************************************
72 * GetNativeSystemInfo (kernelbase.@)
74 void WINAPI DECLSPEC_HOTPATCH GetNativeSystemInfo( SYSTEM_INFO *si )
76 GetSystemInfo( si );
77 if (!is_wow64) return;
78 switch (si->u.s.wProcessorArchitecture)
80 case PROCESSOR_ARCHITECTURE_INTEL:
81 si->u.s.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
82 si->dwProcessorType = PROCESSOR_AMD_X8664;
83 break;
84 default:
85 FIXME( "Add the proper information for %d in wow64 mode\n", si->u.s.wProcessorArchitecture );
90 /***********************************************************************
91 * GetSystemInfo (kernelbase.@)
93 void WINAPI DECLSPEC_HOTPATCH GetSystemInfo( SYSTEM_INFO *si )
95 SYSTEM_BASIC_INFORMATION basic_info;
96 SYSTEM_CPU_INFORMATION cpu_info;
98 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation,
99 &basic_info, sizeof(basic_info), NULL )) ||
100 !set_ntstatus( NtQuerySystemInformation( SystemCpuInformation,
101 &cpu_info, sizeof(cpu_info), NULL )))
102 return;
104 si->u.s.wProcessorArchitecture = cpu_info.Architecture;
105 si->u.s.wReserved = 0;
106 si->dwPageSize = basic_info.PageSize;
107 si->lpMinimumApplicationAddress = basic_info.LowestUserAddress;
108 si->lpMaximumApplicationAddress = basic_info.HighestUserAddress;
109 si->dwActiveProcessorMask = basic_info.ActiveProcessorsAffinityMask;
110 si->dwNumberOfProcessors = basic_info.NumberOfProcessors;
111 si->dwAllocationGranularity = basic_info.AllocationGranularity;
112 si->wProcessorLevel = cpu_info.Level;
113 si->wProcessorRevision = cpu_info.Revision;
115 switch (cpu_info.Architecture)
117 case PROCESSOR_ARCHITECTURE_INTEL:
118 switch (cpu_info.Level)
120 case 3: si->dwProcessorType = PROCESSOR_INTEL_386; break;
121 case 4: si->dwProcessorType = PROCESSOR_INTEL_486; break;
122 case 5:
123 case 6: si->dwProcessorType = PROCESSOR_INTEL_PENTIUM; break;
124 default: si->dwProcessorType = PROCESSOR_INTEL_PENTIUM; break;
126 break;
127 case PROCESSOR_ARCHITECTURE_PPC:
128 switch (cpu_info.Level)
130 case 1: si->dwProcessorType = PROCESSOR_PPC_601; break;
131 case 3:
132 case 6: si->dwProcessorType = PROCESSOR_PPC_603; break;
133 case 4: si->dwProcessorType = PROCESSOR_PPC_604; break;
134 case 9: si->dwProcessorType = PROCESSOR_PPC_604; break;
135 case 20: si->dwProcessorType = PROCESSOR_PPC_620; break;
136 default: si->dwProcessorType = 0;
138 break;
139 case PROCESSOR_ARCHITECTURE_AMD64:
140 si->dwProcessorType = PROCESSOR_AMD_X8664;
141 break;
142 case PROCESSOR_ARCHITECTURE_ARM:
143 switch (cpu_info.Level)
145 case 4: si->dwProcessorType = PROCESSOR_ARM_7TDMI; break;
146 default: si->dwProcessorType = PROCESSOR_ARM920;
148 break;
149 case PROCESSOR_ARCHITECTURE_ARM64:
150 si->dwProcessorType = 0;
151 break;
152 default:
153 FIXME( "Unknown processor architecture %x\n", cpu_info.Architecture );
154 si->dwProcessorType = 0;
155 break;
160 /***********************************************************************
161 * GetSystemFileCacheSize (kernelbase.@)
163 BOOL WINAPI DECLSPEC_HOTPATCH GetSystemFileCacheSize( SIZE_T *mincache, SIZE_T *maxcache, DWORD *flags )
165 FIXME( "stub: %p %p %p\n", mincache, maxcache, flags );
166 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
167 return FALSE;
171 /***********************************************************************
172 * GetWriteWatch (kernelbase.@)
174 UINT WINAPI DECLSPEC_HOTPATCH GetWriteWatch( DWORD flags, void *base, SIZE_T size, void **addresses,
175 ULONG_PTR *count, ULONG *granularity )
177 if (!set_ntstatus( NtGetWriteWatch( GetCurrentProcess(), flags, base, size,
178 addresses, count, granularity )))
179 return ~0u;
180 return 0;
184 /***********************************************************************
185 * MapViewOfFile (kernelbase.@)
187 LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile( HANDLE mapping, DWORD access, DWORD offset_high,
188 DWORD offset_low, SIZE_T count )
190 return MapViewOfFileEx( mapping, access, offset_high, offset_low, count, NULL );
194 /***********************************************************************
195 * MapViewOfFileEx (kernelbase.@)
197 LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileEx( HANDLE handle, DWORD access, DWORD offset_high,
198 DWORD offset_low, SIZE_T count, LPVOID addr )
200 NTSTATUS status;
201 LARGE_INTEGER offset;
202 ULONG protect;
203 BOOL exec;
205 offset.u.LowPart = offset_low;
206 offset.u.HighPart = offset_high;
208 exec = access & FILE_MAP_EXECUTE;
209 access &= ~FILE_MAP_EXECUTE;
211 if (access == FILE_MAP_COPY)
212 protect = exec ? PAGE_EXECUTE_WRITECOPY : PAGE_WRITECOPY;
213 else if (access & FILE_MAP_WRITE)
214 protect = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
215 else if (access & FILE_MAP_READ)
216 protect = exec ? PAGE_EXECUTE_READ : PAGE_READONLY;
217 else protect = PAGE_NOACCESS;
219 if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
220 &count, ViewShare, 0, protect )) < 0)
222 SetLastError( RtlNtStatusToDosError(status) );
223 addr = NULL;
225 return addr;
229 /***********************************************************************
230 * ReadProcessMemory (kernelbase.@)
232 BOOL WINAPI DECLSPEC_HOTPATCH ReadProcessMemory( HANDLE process, const void *addr, void *buffer,
233 SIZE_T size, SIZE_T *bytes_read )
235 return set_ntstatus( NtReadVirtualMemory( process, addr, buffer, size, bytes_read ));
239 /***********************************************************************
240 * ResetWriteWatch (kernelbase.@)
242 UINT WINAPI DECLSPEC_HOTPATCH ResetWriteWatch( void *base, SIZE_T size )
244 if (!set_ntstatus( NtResetWriteWatch( GetCurrentProcess(), base, size )))
245 return ~0u;
246 return 0;
250 /***********************************************************************
251 * SetSystemFileCacheSize (kernelbase.@)
253 BOOL WINAPI DECLSPEC_HOTPATCH SetSystemFileCacheSize( SIZE_T mincache, SIZE_T maxcache, DWORD flags )
255 FIXME( "stub: %ld %ld %d\n", mincache, maxcache, flags );
256 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
257 return FALSE;
261 /***********************************************************************
262 * UnmapViewOfFile (kernelbase.@)
264 BOOL WINAPI DECLSPEC_HOTPATCH UnmapViewOfFile( const void *addr )
266 if (GetVersion() & 0x80000000)
268 MEMORY_BASIC_INFORMATION info;
269 if (!VirtualQuery( addr, &info, sizeof(info) ) || info.AllocationBase != addr)
271 SetLastError( ERROR_INVALID_ADDRESS );
272 return FALSE;
275 return set_ntstatus( NtUnmapViewOfSection( GetCurrentProcess(), (void *)addr ));
279 /***********************************************************************
280 * VirtualAlloc (kernelbase.@)
282 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAlloc( void *addr, SIZE_T size, DWORD type, DWORD protect )
284 return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
288 /***********************************************************************
289 * VirtualAllocEx (kernelbase.@)
291 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocEx( HANDLE process, void *addr, SIZE_T size,
292 DWORD type, DWORD protect )
294 LPVOID ret = addr;
296 if (!set_ntstatus( NtAllocateVirtualMemory( process, &ret, 0, &size, type, protect ))) return NULL;
297 return ret;
301 /***********************************************************************
302 * VirtualFree (kernelbase.@)
304 BOOL WINAPI DECLSPEC_HOTPATCH VirtualFree( void *addr, SIZE_T size, DWORD type )
306 return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
310 /***********************************************************************
311 * VirtualFreeEx (kernelbase.@)
313 BOOL WINAPI DECLSPEC_HOTPATCH VirtualFreeEx( HANDLE process, void *addr, SIZE_T size, DWORD type )
315 return set_ntstatus( NtFreeVirtualMemory( process, &addr, &size, type ));
319 /***********************************************************************
320 * VirtualLock (kernelbase.@)
322 BOOL WINAPI DECLSPEC_HOTPATCH VirtualLock( void *addr, SIZE_T size )
324 return set_ntstatus( NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ));
328 /***********************************************************************
329 * VirtualProtect (kernelbase.@)
331 BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtect( void *addr, SIZE_T size, DWORD new_prot, DWORD *old_prot )
333 return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
337 /***********************************************************************
338 * VirtualProtectEx (kernelbase.@)
340 BOOL WINAPI DECLSPEC_HOTPATCH VirtualProtectEx( HANDLE process, void *addr, SIZE_T size,
341 DWORD new_prot, DWORD *old_prot )
343 DWORD prot;
345 /* Win9x allows passing NULL as old_prot while this fails on NT */
346 if (!old_prot && (GetVersion() & 0x80000000)) old_prot = &prot;
347 return set_ntstatus( NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot ));
351 /***********************************************************************
352 * VirtualQuery (kernelbase.@)
354 SIZE_T WINAPI DECLSPEC_HOTPATCH VirtualQuery( LPCVOID addr, PMEMORY_BASIC_INFORMATION info, SIZE_T len )
356 return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
360 /***********************************************************************
361 * VirtualQueryEx (kernelbase.@)
363 SIZE_T WINAPI DECLSPEC_HOTPATCH VirtualQueryEx( HANDLE process, LPCVOID addr,
364 PMEMORY_BASIC_INFORMATION info, SIZE_T len )
366 SIZE_T ret;
368 if (!set_ntstatus( NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
369 return 0;
370 return ret;
374 /***********************************************************************
375 * VirtualUnlock (kernelbase.@)
377 BOOL WINAPI DECLSPEC_HOTPATCH VirtualUnlock( void *addr, SIZE_T size )
379 return set_ntstatus( NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 ));
383 /***********************************************************************
384 * WriteProcessMemory (kernelbase.@)
386 BOOL WINAPI DECLSPEC_HOTPATCH WriteProcessMemory( HANDLE process, void *addr, const void *buffer,
387 SIZE_T size, SIZE_T *bytes_written )
389 return set_ntstatus( NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ));
393 /* IsBadStringPtrA replacement for kernelbase, to catch exception in debug traces. */
394 BOOL WINAPI IsBadStringPtrA( LPCSTR str, UINT_PTR max )
396 if (!str) return TRUE;
397 __TRY
399 volatile const char *p = str;
400 while (p != str + max) if (!*p++) break;
402 __EXCEPT_PAGE_FAULT
404 return TRUE;
406 __ENDTRY
407 return FALSE;
411 /* IsBadStringPtrW replacement for kernelbase, to catch exception in debug traces. */
412 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT_PTR max )
414 if (!str) return TRUE;
415 __TRY
417 volatile const WCHAR *p = str;
418 while (p != str + max) if (!*p++) break;
420 __EXCEPT_PAGE_FAULT
422 return TRUE;
424 __ENDTRY
425 return FALSE;
429 /***********************************************************************
430 * Heap functions
431 ***********************************************************************/
434 /***********************************************************************
435 * HeapCompact (kernelbase.@)
437 SIZE_T WINAPI DECLSPEC_HOTPATCH HeapCompact( HANDLE heap, DWORD flags )
439 return RtlCompactHeap( heap, flags );
443 /***********************************************************************
444 * HeapCreate (kernelbase.@)
446 HANDLE WINAPI DECLSPEC_HOTPATCH HeapCreate( DWORD flags, SIZE_T init_size, SIZE_T max_size )
448 HANDLE ret = RtlCreateHeap( flags, NULL, max_size, init_size, NULL, NULL );
449 if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
450 return ret;
454 /***********************************************************************
455 * HeapDestroy (kernelbase.@)
457 BOOL WINAPI DECLSPEC_HOTPATCH HeapDestroy( HANDLE heap )
459 if (!RtlDestroyHeap( heap )) return TRUE;
460 SetLastError( ERROR_INVALID_HANDLE );
461 return FALSE;
465 /***********************************************************************
466 * HeapLock (kernelbase.@)
468 BOOL WINAPI DECLSPEC_HOTPATCH HeapLock( HANDLE heap )
470 return RtlLockHeap( heap );
474 /***********************************************************************
475 * HeapQueryInformation (kernelbase.@)
477 BOOL WINAPI HeapQueryInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_class,
478 PVOID info, SIZE_T size, PSIZE_T size_out )
480 return set_ntstatus( RtlQueryHeapInformation( heap, info_class, info, size, size_out ));
484 /***********************************************************************
485 * HeapSetInformation (kernelbase.@)
487 BOOL WINAPI HeapSetInformation( HANDLE heap, HEAP_INFORMATION_CLASS infoclass, PVOID info, SIZE_T size )
489 return set_ntstatus( RtlSetHeapInformation( heap, infoclass, info, size ));
493 /***********************************************************************
494 * HeapUnlock (kernelbase.@)
496 BOOL WINAPI HeapUnlock( HANDLE heap )
498 return RtlUnlockHeap( heap );
502 /***********************************************************************
503 * HeapValidate (kernelbase.@)
505 BOOL WINAPI DECLSPEC_HOTPATCH HeapValidate( HANDLE heap, DWORD flags, LPCVOID ptr )
507 return RtlValidateHeap( heap, flags, ptr );
511 /***********************************************************************
512 * HeapWalk (kernelbase.@)
514 BOOL WINAPI DECLSPEC_HOTPATCH HeapWalk( HANDLE heap, PROCESS_HEAP_ENTRY *entry )
516 return set_ntstatus( RtlWalkHeap( heap, entry ));
520 /***********************************************************************
521 * Global/local heap functions
522 ***********************************************************************/
524 #include "pshpack1.h"
526 struct local_header
528 WORD magic;
529 void *ptr;
530 BYTE flags;
531 BYTE lock;
534 #include "poppack.h"
536 #define MAGIC_LOCAL_USED 0x5342
537 /* align the storage needed for the HLOCAL on an 8-byte boundary thus
538 * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with
539 * size = 8*k, where k=1,2,3,... allocs exactly the given size.
540 * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
541 * the output jpeg's > 1 MB if not */
542 #define HLOCAL_STORAGE (sizeof(HLOCAL) * 2)
544 static inline struct local_header *get_header( HLOCAL hmem )
546 return (struct local_header *)((char *)hmem - 2);
549 static inline HLOCAL get_handle( struct local_header *header )
551 return &header->ptr;
554 static inline BOOL is_pointer( HLOCAL hmem )
556 return !((ULONG_PTR)hmem & 2);
559 /***********************************************************************
560 * GlobalAlloc (kernelbase.@)
562 HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalAlloc( UINT flags, SIZE_T size )
564 /* mask out obsolete flags */
565 flags &= ~(GMEM_NOCOMPACT | GMEM_NOT_BANKED | GMEM_NOTIFY);
567 /* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */
568 if (!(flags & GMEM_MOVEABLE) && !size) size = 1;
570 return LocalAlloc( flags, size );
574 /***********************************************************************
575 * GlobalFree (kernelbase.@)
577 HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL hmem )
579 return LocalFree( hmem );
583 /***********************************************************************
584 * LocalAlloc (kernelbase.@)
586 HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
588 struct local_header *header;
589 DWORD heap_flags = 0;
590 void *ptr;
592 if (flags & LMEM_ZEROINIT) heap_flags = HEAP_ZERO_MEMORY;
594 if (!(flags & LMEM_MOVEABLE)) /* pointer */
596 ptr = HeapAlloc( GetProcessHeap(), heap_flags, size );
597 TRACE( "(flags=%04x) returning %p\n", flags, ptr );
598 return ptr;
601 if (size > INT_MAX - HLOCAL_STORAGE)
603 SetLastError( ERROR_OUTOFMEMORY );
604 return 0;
606 if (!(header = HeapAlloc( GetProcessHeap(), 0, sizeof(*header) ))) return 0;
608 header->magic = MAGIC_LOCAL_USED;
609 header->flags = flags >> 8;
610 header->lock = 0;
612 if (size)
614 if (!(ptr = HeapAlloc(GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE )))
616 HeapFree( GetProcessHeap(), 0, header );
617 return 0;
619 *(HLOCAL *)ptr = get_handle( header );
620 header->ptr = (char *)ptr + HLOCAL_STORAGE;
622 else header->ptr = NULL;
624 TRACE( "(flags=%04x) returning handle %p pointer %p\n",
625 flags, get_handle( header ), header->ptr );
626 return get_handle( header );
630 /***********************************************************************
631 * LocalFree (kernelbase.@)
633 HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL hmem )
635 struct local_header *header;
636 HLOCAL ret;
638 RtlLockHeap( GetProcessHeap() );
639 __TRY
641 ret = 0;
642 if (is_pointer(hmem)) /* POINTER */
644 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, hmem ))
646 SetLastError( ERROR_INVALID_HANDLE );
647 ret = hmem;
650 else /* HANDLE */
652 header = get_header( hmem );
653 if (header->magic == MAGIC_LOCAL_USED)
655 header->magic = 0xdead;
656 if (header->ptr)
658 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE,
659 (char *)header->ptr - HLOCAL_STORAGE ))
660 ret = hmem;
662 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, header )) ret = hmem;
664 else
666 WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic );
667 SetLastError( ERROR_INVALID_HANDLE );
668 ret = hmem;
672 __EXCEPT_PAGE_FAULT
674 WARN( "invalid handle %p\n", hmem );
675 SetLastError( ERROR_INVALID_HANDLE );
676 ret = hmem;
678 __ENDTRY
679 RtlUnlockHeap( GetProcessHeap() );
680 return ret;
684 /***********************************************************************
685 * LocalLock (kernelbase.@)
687 LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL hmem )
689 void *ret = NULL;
691 if (is_pointer( hmem ))
693 __TRY
695 volatile char *p = hmem;
696 *p |= 0;
698 __EXCEPT_PAGE_FAULT
700 return NULL;
702 __ENDTRY
703 return hmem;
706 RtlLockHeap( GetProcessHeap() );
707 __TRY
709 struct local_header *header = get_header( hmem );
710 if (header->magic == MAGIC_LOCAL_USED)
712 ret = header->ptr;
713 if (!header->ptr) SetLastError( ERROR_DISCARDED );
714 else if (header->lock < LMEM_LOCKCOUNT) header->lock++;
716 else
718 WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic );
719 SetLastError( ERROR_INVALID_HANDLE );
722 __EXCEPT_PAGE_FAULT
724 WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
725 SetLastError( ERROR_INVALID_HANDLE );
727 __ENDTRY
728 RtlUnlockHeap( GetProcessHeap() );
729 return ret;
733 /***********************************************************************
734 * LocalReAlloc (kernelbase.@)
736 HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL hmem, SIZE_T size, UINT flags )
738 struct local_header *header;
739 void *ptr;
740 HLOCAL ret = 0;
741 DWORD heap_flags = (flags & LMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
743 RtlLockHeap( GetProcessHeap() );
744 if (flags & LMEM_MODIFY) /* modify flags */
746 if (is_pointer( hmem ) && (flags & LMEM_MOVEABLE))
748 /* make a fixed block moveable
749 * actually only NT is able to do this. But it's soo simple
751 if (hmem == 0)
753 WARN( "null handle\n");
754 SetLastError( ERROR_NOACCESS );
756 else
758 size = RtlSizeHeap( GetProcessHeap(), 0, hmem );
759 ret = LocalAlloc( flags, size );
760 ptr = LocalLock( ret );
761 memcpy( ptr, hmem, size );
762 LocalUnlock( ret );
763 LocalFree( hmem );
766 else if (!is_pointer( hmem ) && (flags & LMEM_DISCARDABLE))
768 /* change the flags to make our block "discardable" */
769 header = get_header( hmem );
770 header->flags |= LMEM_DISCARDABLE >> 8;
771 ret = hmem;
773 else SetLastError( ERROR_INVALID_PARAMETER );
775 else
777 if (is_pointer( hmem ))
779 /* reallocate fixed memory */
780 if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
781 ret = HeapReAlloc( GetProcessHeap(), heap_flags, hmem, size );
783 else
785 /* reallocate a moveable block */
786 header = get_header( hmem );
787 if (size != 0)
789 if (size <= INT_MAX - HLOCAL_STORAGE)
791 if (header->ptr)
793 if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags,
794 (char *)header->ptr - HLOCAL_STORAGE,
795 size + HLOCAL_STORAGE )))
797 header->ptr = (char *)ptr + HLOCAL_STORAGE;
798 ret = hmem;
801 else
803 if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE )))
805 *(HLOCAL *)ptr = hmem;
806 header->ptr = (char *)ptr + HLOCAL_STORAGE;
807 ret = hmem;
811 else SetLastError( ERROR_OUTOFMEMORY );
813 else
815 if (header->lock == 0)
817 if (header->ptr)
819 HeapFree( GetProcessHeap(), 0, (char *)header->ptr - HLOCAL_STORAGE );
820 header->ptr = NULL;
822 ret = hmem;
824 else WARN( "not freeing memory associated with locked handle\n" );
828 RtlUnlockHeap( GetProcessHeap() );
829 return ret;
833 /***********************************************************************
834 * LocalUnlock (kernelbase.@)
836 BOOL WINAPI DECLSPEC_HOTPATCH LocalUnlock( HLOCAL hmem )
838 BOOL ret = FALSE;
840 if (is_pointer( hmem ))
842 SetLastError( ERROR_NOT_LOCKED );
843 return FALSE;
846 RtlLockHeap( GetProcessHeap() );
847 __TRY
849 struct local_header *header = get_header( hmem );
850 if (header->magic == MAGIC_LOCAL_USED)
852 if (header->lock)
854 header->lock--;
855 ret = (header->lock != 0);
856 if (!ret) SetLastError( NO_ERROR );
858 else
860 WARN( "%p not locked\n", hmem );
861 SetLastError( ERROR_NOT_LOCKED );
864 else
866 WARN( "invalid handle %p (Magic: 0x%04x)\n", hmem, header->magic );
867 SetLastError( ERROR_INVALID_HANDLE );
870 __EXCEPT_PAGE_FAULT
872 WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
873 SetLastError( ERROR_INVALID_PARAMETER );
875 __ENDTRY
876 RtlUnlockHeap( GetProcessHeap() );
877 return ret;
881 /***********************************************************************
882 * Memory resource functions
883 ***********************************************************************/
886 /***********************************************************************
887 * CreateMemoryResourceNotification (kernelbase.@)
889 HANDLE WINAPI DECLSPEC_HOTPATCH CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE type )
891 static const WCHAR lowmemW[] =
892 {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
893 '\\','L','o','w','M','e','m','o','r','y','C','o','n','d','i','t','i','o','n',0};
894 static const WCHAR highmemW[] =
895 {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
896 '\\','H','i','g','h','M','e','m','o','r','y','C','o','n','d','i','t','i','o','n',0};
897 HANDLE ret;
898 UNICODE_STRING nameW;
899 OBJECT_ATTRIBUTES attr;
901 switch (type)
903 case LowMemoryResourceNotification:
904 RtlInitUnicodeString( &nameW, lowmemW );
905 break;
906 case HighMemoryResourceNotification:
907 RtlInitUnicodeString( &nameW, highmemW );
908 break;
909 default:
910 SetLastError( ERROR_INVALID_PARAMETER );
911 return 0;
914 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
915 if (!set_ntstatus( NtOpenEvent( &ret, EVENT_ALL_ACCESS, &attr ))) return 0;
916 return ret;
919 /***********************************************************************
920 * QueryMemoryResourceNotification (kernelbase.@)
922 BOOL WINAPI DECLSPEC_HOTPATCH QueryMemoryResourceNotification( HANDLE handle, BOOL *state )
924 switch (WaitForSingleObject( handle, 0 ))
926 case WAIT_OBJECT_0:
927 *state = TRUE;
928 return TRUE;
929 case WAIT_TIMEOUT:
930 *state = FALSE;
931 return TRUE;
933 SetLastError( ERROR_INVALID_PARAMETER );
934 return FALSE;
938 /***********************************************************************
939 * Physical memory functions
940 ***********************************************************************/
943 /***********************************************************************
944 * AllocateUserPhysicalPages (kernelbase.@)
946 BOOL WINAPI DECLSPEC_HOTPATCH AllocateUserPhysicalPages( HANDLE process, ULONG_PTR *pages,
947 ULONG_PTR *userarray )
949 FIXME( "stub: %p %p %p\n", process, pages, userarray );
950 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
951 return FALSE;
955 /***********************************************************************
956 * FreeUserPhysicalPages (kernelbase.@)
958 BOOL WINAPI DECLSPEC_HOTPATCH FreeUserPhysicalPages( HANDLE process, ULONG_PTR *pages,
959 ULONG_PTR *userarray )
961 FIXME( "stub: %p %p %p\n", process, pages, userarray );
962 *pages = 0;
963 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
964 return FALSE;
968 /***********************************************************************
969 * GetPhysicallyInstalledSystemMemory (kernelbase.@)
971 BOOL WINAPI DECLSPEC_HOTPATCH GetPhysicallyInstalledSystemMemory( ULONGLONG *memory )
973 MEMORYSTATUSEX status;
975 if (!memory)
977 SetLastError( ERROR_INVALID_PARAMETER );
978 return FALSE;
980 status.dwLength = sizeof(status);
981 GlobalMemoryStatusEx( &status );
982 *memory = status.ullTotalPhys / 1024;
983 return TRUE;
987 /***********************************************************************
988 * GlobalMemoryStatusEx (kernelbase.@)
990 BOOL WINAPI DECLSPEC_HOTPATCH GlobalMemoryStatusEx( MEMORYSTATUSEX *status )
992 static MEMORYSTATUSEX cached_status;
993 static DWORD last_check;
994 SYSTEM_BASIC_INFORMATION basic_info;
995 SYSTEM_PERFORMANCE_INFORMATION perf_info;
997 if (status->dwLength != sizeof(*status))
999 SetLastError( ERROR_INVALID_PARAMETER );
1000 return FALSE;
1002 if ((NtGetTickCount() - last_check) < 1000)
1004 *status = cached_status;
1005 return TRUE;
1007 last_check = NtGetTickCount();
1009 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation,
1010 &basic_info, sizeof(basic_info), NULL )) ||
1011 !set_ntstatus( NtQuerySystemInformation( SystemPerformanceInformation,
1012 &perf_info, sizeof(perf_info), NULL)))
1013 return FALSE;
1015 status->dwMemoryLoad = 0;
1016 status->ullTotalPhys = perf_info.TotalCommitLimit;
1017 status->ullAvailPhys = perf_info.AvailablePages;
1018 status->ullTotalPageFile = perf_info.TotalCommitLimit + 1; /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */
1019 status->ullAvailPageFile = status->ullTotalPageFile - perf_info.TotalCommittedPages;
1020 status->ullTotalVirtual = (ULONG_PTR)basic_info.HighestUserAddress - (ULONG_PTR)basic_info.LowestUserAddress;
1021 status->ullAvailVirtual = status->ullTotalVirtual - 64 * 1024; /* FIXME */
1022 status->ullAvailExtendedVirtual = 0;
1024 status->ullTotalPhys *= basic_info.PageSize;
1025 status->ullAvailPhys *= basic_info.PageSize;
1026 status->ullTotalPageFile *= basic_info.PageSize;
1027 status->ullAvailPageFile *= basic_info.PageSize;
1029 if (status->ullTotalPhys)
1030 status->dwMemoryLoad = (status->ullTotalPhys - status->ullAvailPhys) / (status->ullTotalPhys / 100);
1032 TRACE_(virtual)( "MemoryLoad %d, TotalPhys %s, AvailPhys %s, TotalPageFile %s,"
1033 "AvailPageFile %s, TotalVirtual %s, AvailVirtual %s\n",
1034 status->dwMemoryLoad, wine_dbgstr_longlong(status->ullTotalPhys),
1035 wine_dbgstr_longlong(status->ullAvailPhys), wine_dbgstr_longlong(status->ullTotalPageFile),
1036 wine_dbgstr_longlong(status->ullAvailPageFile), wine_dbgstr_longlong(status->ullTotalVirtual),
1037 wine_dbgstr_longlong(status->ullAvailVirtual) );
1039 cached_status = *status;
1040 return TRUE;
1044 /***********************************************************************
1045 * MapUserPhysicalPages (kernelbase.@)
1047 BOOL WINAPI DECLSPEC_HOTPATCH MapUserPhysicalPages( void *addr, ULONG_PTR page_count, ULONG_PTR *pages )
1049 FIXME( "stub: %p %lu %p\n", addr, page_count, pages );
1050 *pages = 0;
1051 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1052 return FALSE;
1056 /***********************************************************************
1057 * NUMA functions
1058 ***********************************************************************/
1061 /***********************************************************************
1062 * AllocateUserPhysicalPagesNuma (kernelbase.@)
1064 BOOL WINAPI DECLSPEC_HOTPATCH AllocateUserPhysicalPagesNuma( HANDLE process, ULONG_PTR *pages,
1065 ULONG_PTR *userarray, DWORD node )
1067 if (node) FIXME( "Ignoring preferred node %u\n", node );
1068 return AllocateUserPhysicalPages( process, pages, userarray );
1072 /***********************************************************************
1073 * CreateFileMappingNumaW (kernelbase.@)
1075 HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileMappingNumaW( HANDLE file, LPSECURITY_ATTRIBUTES sa,
1076 DWORD protect, DWORD size_high, DWORD size_low,
1077 LPCWSTR name, DWORD node )
1079 if (node) FIXME( "Ignoring preferred node %u\n", node );
1080 return CreateFileMappingW( file, sa, protect, size_high, size_low, name );
1084 /***********************************************************************
1085 * GetLogicalProcessorInformation (kernelbase.@)
1087 BOOL WINAPI DECLSPEC_HOTPATCH GetLogicalProcessorInformation( SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer,
1088 DWORD *len )
1090 NTSTATUS status;
1092 if (!len)
1094 SetLastError( ERROR_INVALID_PARAMETER );
1095 return FALSE;
1097 status = NtQuerySystemInformation( SystemLogicalProcessorInformation, buffer, *len, len );
1098 if (status == STATUS_INFO_LENGTH_MISMATCH) status = STATUS_BUFFER_TOO_SMALL;
1099 return set_ntstatus( status );
1103 /***********************************************************************
1104 * GetLogicalProcessorInformationEx (kernelbase.@)
1106 BOOL WINAPI DECLSPEC_HOTPATCH GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP relationship,
1107 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, DWORD *len )
1109 NTSTATUS status;
1111 if (!len)
1113 SetLastError( ERROR_INVALID_PARAMETER );
1114 return FALSE;
1116 status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship,
1117 sizeof(relationship), buffer, *len, len );
1118 if (status == STATUS_INFO_LENGTH_MISMATCH) status = STATUS_BUFFER_TOO_SMALL;
1119 return set_ntstatus( status );
1123 /**********************************************************************
1124 * GetNumaHighestNodeNumber (kernelbase.@)
1126 BOOL WINAPI DECLSPEC_HOTPATCH GetNumaHighestNodeNumber( ULONG *node )
1128 FIXME( "semi-stub: %p\n", node );
1129 *node = 0;
1130 return TRUE;
1134 /**********************************************************************
1135 * GetNumaNodeProcessorMaskEx (kernelbase.@)
1137 BOOL WINAPI DECLSPEC_HOTPATCH GetNumaNodeProcessorMaskEx( USHORT node, GROUP_AFFINITY *mask )
1139 FIXME( "stub: %hu %p\n", node, mask );
1140 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1141 return FALSE;
1145 /***********************************************************************
1146 * GetNumaProximityNodeEx (kernelbase.@)
1148 BOOL WINAPI DECLSPEC_HOTPATCH GetNumaProximityNodeEx( ULONG proximity_id, USHORT *node )
1150 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1151 return FALSE;
1155 /***********************************************************************
1156 * MapViewOfFileExNuma (kernelbase.@)
1158 LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileExNuma( HANDLE handle, DWORD access, DWORD offset_high,
1159 DWORD offset_low, SIZE_T count, LPVOID addr,
1160 DWORD node )
1162 if (node) FIXME( "Ignoring preferred node %u\n", node );
1163 return MapViewOfFileEx( handle, access, offset_high, offset_low, count, addr );
1167 /***********************************************************************
1168 * VirtualAllocExNuma (kernelbase.@)
1170 LPVOID WINAPI DECLSPEC_HOTPATCH VirtualAllocExNuma( HANDLE process, void *addr, SIZE_T size,
1171 DWORD type, DWORD protect, DWORD node )
1173 if (node) FIXME( "Ignoring preferred node %u\n", node );
1174 return VirtualAllocEx( process, addr, size, type, protect );
1178 /***********************************************************************
1179 * Firmware functions
1180 ***********************************************************************/
1183 /***********************************************************************
1184 * EnumSystemFirmwareTable (kernelbase.@)
1186 UINT WINAPI EnumSystemFirmwareTables( DWORD provider, void *buffer, DWORD size )
1188 FIXME( "(0x%08x, %p, %d)\n", provider, buffer, size );
1189 return 0;
1193 /***********************************************************************
1194 * GetSystemFirmwareTable (kernelbase.@)
1196 UINT WINAPI GetSystemFirmwareTable( DWORD provider, DWORD id, void *buffer, DWORD size )
1198 SYSTEM_FIRMWARE_TABLE_INFORMATION *info;
1199 ULONG buffer_size = offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer ) + size;
1201 TRACE( "(0x%08x, 0x%08x, %p, %d)\n", provider, id, buffer, size );
1203 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, buffer_size )))
1205 SetLastError( ERROR_OUTOFMEMORY );
1206 return 0;
1209 info->ProviderSignature = provider;
1210 info->Action = SystemFirmwareTable_Get;
1211 info->TableID = id;
1213 set_ntstatus( NtQuerySystemInformation( SystemFirmwareTableInformation,
1214 info, buffer_size, &buffer_size ));
1215 buffer_size -= offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer );
1216 if (buffer_size <= size) memcpy( buffer, info->TableBuffer, buffer_size );
1218 HeapFree( GetProcessHeap(), 0, info );
1219 return buffer_size;