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
25 #include <sys/types.h>
28 #define WIN32_NO_STATUS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
38 #include "kernelbase.h"
39 #include "wine/exception.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(heap
);
43 WINE_DECLARE_DEBUG_CHANNEL(virtual);
46 /***********************************************************************
47 * Virtual memory functions
48 ***********************************************************************/
51 /***********************************************************************
52 * FlushViewOfFile (kernelbase.@)
54 BOOL WINAPI DECLSPEC_HOTPATCH
FlushViewOfFile( const void *base
, SIZE_T size
)
56 NTSTATUS status
= NtFlushVirtualMemory( GetCurrentProcess(), &base
, &size
, 0 );
58 if (status
== STATUS_NOT_MAPPED_DATA
) status
= STATUS_SUCCESS
;
59 return set_ntstatus( status
);
63 /***********************************************************************
64 * GetLargePageMinimum (kernelbase.@)
66 SIZE_T WINAPI
GetLargePageMinimum(void)
68 return 2 * 1024 * 1024;
72 /***********************************************************************
73 * GetNativeSystemInfo (kernelbase.@)
75 void WINAPI DECLSPEC_HOTPATCH
GetNativeSystemInfo( SYSTEM_INFO
*si
)
77 USHORT current_machine
, native_machine
;
80 RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t_machine
, &native_machine
);
81 if (!current_machine
) return;
82 switch (native_machine
)
84 case PROCESSOR_ARCHITECTURE_AMD64
:
85 si
->u
.s
.wProcessorArchitecture
= PROCESSOR_ARCHITECTURE_AMD64
;
86 si
->dwProcessorType
= PROCESSOR_AMD_X8664
;
88 case PROCESSOR_ARCHITECTURE_ARM64
:
89 si
->u
.s
.wProcessorArchitecture
= PROCESSOR_ARCHITECTURE_ARM64
;
90 si
->dwProcessorType
= 0;
93 FIXME( "Add the proper information for %d in wow64 mode\n", si
->u
.s
.wProcessorArchitecture
);
98 /***********************************************************************
99 * GetSystemInfo (kernelbase.@)
101 void WINAPI DECLSPEC_HOTPATCH
GetSystemInfo( SYSTEM_INFO
*si
)
103 SYSTEM_BASIC_INFORMATION basic_info
;
104 SYSTEM_CPU_INFORMATION cpu_info
;
106 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation
,
107 &basic_info
, sizeof(basic_info
), NULL
)) ||
108 !set_ntstatus( NtQuerySystemInformation( SystemCpuInformation
,
109 &cpu_info
, sizeof(cpu_info
), NULL
)))
112 si
->u
.s
.wProcessorArchitecture
= cpu_info
.Architecture
;
113 si
->u
.s
.wReserved
= 0;
114 si
->dwPageSize
= basic_info
.PageSize
;
115 si
->lpMinimumApplicationAddress
= basic_info
.LowestUserAddress
;
116 si
->lpMaximumApplicationAddress
= basic_info
.HighestUserAddress
;
117 si
->dwActiveProcessorMask
= basic_info
.ActiveProcessorsAffinityMask
;
118 si
->dwNumberOfProcessors
= basic_info
.NumberOfProcessors
;
119 si
->dwAllocationGranularity
= basic_info
.AllocationGranularity
;
120 si
->wProcessorLevel
= cpu_info
.Level
;
121 si
->wProcessorRevision
= cpu_info
.Revision
;
123 switch (cpu_info
.Architecture
)
125 case PROCESSOR_ARCHITECTURE_INTEL
:
126 switch (cpu_info
.Level
)
128 case 3: si
->dwProcessorType
= PROCESSOR_INTEL_386
; break;
129 case 4: si
->dwProcessorType
= PROCESSOR_INTEL_486
; break;
131 case 6: si
->dwProcessorType
= PROCESSOR_INTEL_PENTIUM
; break;
132 default: si
->dwProcessorType
= PROCESSOR_INTEL_PENTIUM
; break;
135 case PROCESSOR_ARCHITECTURE_PPC
:
136 switch (cpu_info
.Level
)
138 case 1: si
->dwProcessorType
= PROCESSOR_PPC_601
; break;
140 case 6: si
->dwProcessorType
= PROCESSOR_PPC_603
; break;
141 case 4: si
->dwProcessorType
= PROCESSOR_PPC_604
; break;
142 case 9: si
->dwProcessorType
= PROCESSOR_PPC_604
; break;
143 case 20: si
->dwProcessorType
= PROCESSOR_PPC_620
; break;
144 default: si
->dwProcessorType
= 0;
147 case PROCESSOR_ARCHITECTURE_AMD64
:
148 si
->dwProcessorType
= PROCESSOR_AMD_X8664
;
150 case PROCESSOR_ARCHITECTURE_ARM
:
151 switch (cpu_info
.Level
)
153 case 4: si
->dwProcessorType
= PROCESSOR_ARM_7TDMI
; break;
154 default: si
->dwProcessorType
= PROCESSOR_ARM920
;
157 case PROCESSOR_ARCHITECTURE_ARM64
:
158 si
->dwProcessorType
= 0;
161 FIXME( "Unknown processor architecture %x\n", cpu_info
.Architecture
);
162 si
->dwProcessorType
= 0;
168 /***********************************************************************
169 * GetSystemFileCacheSize (kernelbase.@)
171 BOOL WINAPI DECLSPEC_HOTPATCH
GetSystemFileCacheSize( SIZE_T
*mincache
, SIZE_T
*maxcache
, DWORD
*flags
)
173 FIXME( "stub: %p %p %p\n", mincache
, maxcache
, flags
);
174 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
179 /***********************************************************************
180 * GetWriteWatch (kernelbase.@)
182 UINT WINAPI DECLSPEC_HOTPATCH
GetWriteWatch( DWORD flags
, void *base
, SIZE_T size
, void **addresses
,
183 ULONG_PTR
*count
, ULONG
*granularity
)
185 if (!set_ntstatus( NtGetWriteWatch( GetCurrentProcess(), flags
, base
, size
,
186 addresses
, count
, granularity
)))
192 /***********************************************************************
193 * MapViewOfFile (kernelbase.@)
195 LPVOID WINAPI DECLSPEC_HOTPATCH
MapViewOfFile( HANDLE mapping
, DWORD access
, DWORD offset_high
,
196 DWORD offset_low
, SIZE_T count
)
198 return MapViewOfFileEx( mapping
, access
, offset_high
, offset_low
, count
, NULL
);
202 /***********************************************************************
203 * MapViewOfFileEx (kernelbase.@)
205 LPVOID WINAPI DECLSPEC_HOTPATCH
MapViewOfFileEx( HANDLE handle
, DWORD access
, DWORD offset_high
,
206 DWORD offset_low
, SIZE_T count
, LPVOID addr
)
209 LARGE_INTEGER offset
;
213 offset
.u
.LowPart
= offset_low
;
214 offset
.u
.HighPart
= offset_high
;
216 exec
= access
& FILE_MAP_EXECUTE
;
217 access
&= ~FILE_MAP_EXECUTE
;
219 if (access
== FILE_MAP_COPY
)
220 protect
= exec
? PAGE_EXECUTE_WRITECOPY
: PAGE_WRITECOPY
;
221 else if (access
& FILE_MAP_WRITE
)
222 protect
= exec
? PAGE_EXECUTE_READWRITE
: PAGE_READWRITE
;
223 else if (access
& FILE_MAP_READ
)
224 protect
= exec
? PAGE_EXECUTE_READ
: PAGE_READONLY
;
225 else protect
= PAGE_NOACCESS
;
227 if ((status
= NtMapViewOfSection( handle
, GetCurrentProcess(), &addr
, 0, 0, &offset
,
228 &count
, ViewShare
, 0, protect
)) < 0)
230 SetLastError( RtlNtStatusToDosError(status
) );
237 /***********************************************************************
238 * ReadProcessMemory (kernelbase.@)
240 BOOL WINAPI DECLSPEC_HOTPATCH
ReadProcessMemory( HANDLE process
, const void *addr
, void *buffer
,
241 SIZE_T size
, SIZE_T
*bytes_read
)
243 return set_ntstatus( NtReadVirtualMemory( process
, addr
, buffer
, size
, bytes_read
));
247 /***********************************************************************
248 * ResetWriteWatch (kernelbase.@)
250 UINT WINAPI DECLSPEC_HOTPATCH
ResetWriteWatch( void *base
, SIZE_T size
)
252 if (!set_ntstatus( NtResetWriteWatch( GetCurrentProcess(), base
, size
)))
258 /***********************************************************************
259 * SetSystemFileCacheSize (kernelbase.@)
261 BOOL WINAPI DECLSPEC_HOTPATCH
SetSystemFileCacheSize( SIZE_T mincache
, SIZE_T maxcache
, DWORD flags
)
263 FIXME( "stub: %ld %ld %d\n", mincache
, maxcache
, flags
);
264 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
269 /***********************************************************************
270 * UnmapViewOfFile (kernelbase.@)
272 BOOL WINAPI DECLSPEC_HOTPATCH
UnmapViewOfFile( const void *addr
)
274 if (GetVersion() & 0x80000000)
276 MEMORY_BASIC_INFORMATION info
;
277 if (!VirtualQuery( addr
, &info
, sizeof(info
) ) || info
.AllocationBase
!= addr
)
279 SetLastError( ERROR_INVALID_ADDRESS
);
283 return set_ntstatus( NtUnmapViewOfSection( GetCurrentProcess(), (void *)addr
));
287 /***********************************************************************
288 * VirtualAlloc (kernelbase.@)
290 LPVOID WINAPI DECLSPEC_HOTPATCH
VirtualAlloc( void *addr
, SIZE_T size
, DWORD type
, DWORD protect
)
292 return VirtualAllocEx( GetCurrentProcess(), addr
, size
, type
, protect
);
296 /***********************************************************************
297 * VirtualAllocEx (kernelbase.@)
299 LPVOID WINAPI DECLSPEC_HOTPATCH
VirtualAllocEx( HANDLE process
, void *addr
, SIZE_T size
,
300 DWORD type
, DWORD protect
)
304 if (!set_ntstatus( NtAllocateVirtualMemory( process
, &ret
, 0, &size
, type
, protect
))) return NULL
;
309 /***********************************************************************
310 * VirtualAlloc2 (kernelbase.@)
312 LPVOID WINAPI DECLSPEC_HOTPATCH
VirtualAlloc2( HANDLE process
, void *addr
, SIZE_T size
,
313 DWORD type
, DWORD protect
,
314 MEM_EXTENDED_PARAMETER
*parameters
, ULONG count
)
318 if (!set_ntstatus( NtAllocateVirtualMemoryEx( process
, &ret
, &size
, type
, protect
, parameters
, count
)))
324 /***********************************************************************
325 * VirtualAllocFromApp (kernelbase.@)
327 LPVOID WINAPI DECLSPEC_HOTPATCH
VirtualAllocFromApp( void *addr
, SIZE_T size
,
328 DWORD type
, DWORD protect
)
332 TRACE_(virtual)( "addr %p, size %p, type %#x, protect %#x.\n", addr
, (void *)size
, type
, protect
);
334 if (protect
== PAGE_EXECUTE
|| protect
== PAGE_EXECUTE_READ
|| protect
== PAGE_EXECUTE_READWRITE
335 || protect
== PAGE_EXECUTE_WRITECOPY
)
337 SetLastError( ERROR_INVALID_PARAMETER
);
341 if (!set_ntstatus( NtAllocateVirtualMemory( GetCurrentProcess(), &ret
, 0, &size
, type
, protect
))) return NULL
;
346 /***********************************************************************
347 * VirtualFree (kernelbase.@)
349 BOOL WINAPI DECLSPEC_HOTPATCH
VirtualFree( void *addr
, SIZE_T size
, DWORD type
)
351 return VirtualFreeEx( GetCurrentProcess(), addr
, size
, type
);
355 /***********************************************************************
356 * VirtualFreeEx (kernelbase.@)
358 BOOL WINAPI DECLSPEC_HOTPATCH
VirtualFreeEx( HANDLE process
, void *addr
, SIZE_T size
, DWORD type
)
360 return set_ntstatus( NtFreeVirtualMemory( process
, &addr
, &size
, type
));
364 /***********************************************************************
365 * VirtualLock (kernelbase.@)
367 BOOL WINAPI DECLSPEC_HOTPATCH
VirtualLock( void *addr
, SIZE_T size
)
369 return set_ntstatus( NtLockVirtualMemory( GetCurrentProcess(), &addr
, &size
, 1 ));
373 /***********************************************************************
374 * VirtualProtect (kernelbase.@)
376 BOOL WINAPI DECLSPEC_HOTPATCH
VirtualProtect( void *addr
, SIZE_T size
, DWORD new_prot
, DWORD
*old_prot
)
378 return VirtualProtectEx( GetCurrentProcess(), addr
, size
, new_prot
, old_prot
);
382 /***********************************************************************
383 * VirtualProtectEx (kernelbase.@)
385 BOOL WINAPI DECLSPEC_HOTPATCH
VirtualProtectEx( HANDLE process
, void *addr
, SIZE_T size
,
386 DWORD new_prot
, DWORD
*old_prot
)
390 /* Win9x allows passing NULL as old_prot while this fails on NT */
391 if (!old_prot
&& (GetVersion() & 0x80000000)) old_prot
= &prot
;
392 return set_ntstatus( NtProtectVirtualMemory( process
, &addr
, &size
, new_prot
, old_prot
));
396 /***********************************************************************
397 * VirtualQuery (kernelbase.@)
399 SIZE_T WINAPI DECLSPEC_HOTPATCH
VirtualQuery( LPCVOID addr
, PMEMORY_BASIC_INFORMATION info
, SIZE_T len
)
401 return VirtualQueryEx( GetCurrentProcess(), addr
, info
, len
);
405 /***********************************************************************
406 * VirtualQueryEx (kernelbase.@)
408 SIZE_T WINAPI DECLSPEC_HOTPATCH
VirtualQueryEx( HANDLE process
, LPCVOID addr
,
409 PMEMORY_BASIC_INFORMATION info
, SIZE_T len
)
413 if (!set_ntstatus( NtQueryVirtualMemory( process
, addr
, MemoryBasicInformation
, info
, len
, &ret
)))
419 /***********************************************************************
420 * VirtualUnlock (kernelbase.@)
422 BOOL WINAPI DECLSPEC_HOTPATCH
VirtualUnlock( void *addr
, SIZE_T size
)
424 return set_ntstatus( NtUnlockVirtualMemory( GetCurrentProcess(), &addr
, &size
, 1 ));
428 /***********************************************************************
429 * WriteProcessMemory (kernelbase.@)
431 BOOL WINAPI DECLSPEC_HOTPATCH
WriteProcessMemory( HANDLE process
, void *addr
, const void *buffer
,
432 SIZE_T size
, SIZE_T
*bytes_written
)
434 return set_ntstatus( NtWriteVirtualMemory( process
, addr
, buffer
, size
, bytes_written
));
438 /* IsBadStringPtrA replacement for kernelbase, to catch exception in debug traces. */
439 BOOL WINAPI
IsBadStringPtrA( LPCSTR str
, UINT_PTR max
)
441 if (!str
) return TRUE
;
444 volatile const char *p
= str
;
445 while (p
!= str
+ max
) if (!*p
++) break;
456 /* IsBadStringPtrW replacement for kernelbase, to catch exception in debug traces. */
457 BOOL WINAPI
IsBadStringPtrW( LPCWSTR str
, UINT_PTR max
)
459 if (!str
) return TRUE
;
462 volatile const WCHAR
*p
= str
;
463 while (p
!= str
+ max
) if (!*p
++) break;
474 /***********************************************************************
476 ***********************************************************************/
479 /***********************************************************************
480 * HeapCompact (kernelbase.@)
482 SIZE_T WINAPI DECLSPEC_HOTPATCH
HeapCompact( HANDLE heap
, DWORD flags
)
484 return RtlCompactHeap( heap
, flags
);
488 /***********************************************************************
489 * HeapCreate (kernelbase.@)
491 HANDLE WINAPI DECLSPEC_HOTPATCH
HeapCreate( DWORD flags
, SIZE_T init_size
, SIZE_T max_size
)
493 HANDLE ret
= RtlCreateHeap( flags
, NULL
, max_size
, init_size
, NULL
, NULL
);
494 if (!ret
) SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
499 /***********************************************************************
500 * HeapDestroy (kernelbase.@)
502 BOOL WINAPI DECLSPEC_HOTPATCH
HeapDestroy( HANDLE heap
)
504 if (!RtlDestroyHeap( heap
)) return TRUE
;
505 SetLastError( ERROR_INVALID_HANDLE
);
510 /***********************************************************************
511 * HeapLock (kernelbase.@)
513 BOOL WINAPI DECLSPEC_HOTPATCH
HeapLock( HANDLE heap
)
515 return RtlLockHeap( heap
);
519 /***********************************************************************
520 * HeapQueryInformation (kernelbase.@)
522 BOOL WINAPI
HeapQueryInformation( HANDLE heap
, HEAP_INFORMATION_CLASS info_class
,
523 PVOID info
, SIZE_T size
, PSIZE_T size_out
)
525 return set_ntstatus( RtlQueryHeapInformation( heap
, info_class
, info
, size
, size_out
));
529 /***********************************************************************
530 * HeapSetInformation (kernelbase.@)
532 BOOL WINAPI
HeapSetInformation( HANDLE heap
, HEAP_INFORMATION_CLASS infoclass
, PVOID info
, SIZE_T size
)
534 return set_ntstatus( RtlSetHeapInformation( heap
, infoclass
, info
, size
));
538 /***********************************************************************
539 * HeapUnlock (kernelbase.@)
541 BOOL WINAPI
HeapUnlock( HANDLE heap
)
543 return RtlUnlockHeap( heap
);
547 /***********************************************************************
548 * HeapValidate (kernelbase.@)
550 BOOL WINAPI DECLSPEC_HOTPATCH
HeapValidate( HANDLE heap
, DWORD flags
, LPCVOID ptr
)
552 return RtlValidateHeap( heap
, flags
, ptr
);
556 /***********************************************************************
557 * HeapWalk (kernelbase.@)
559 BOOL WINAPI DECLSPEC_HOTPATCH
HeapWalk( HANDLE heap
, PROCESS_HEAP_ENTRY
*entry
)
561 return set_ntstatus( RtlWalkHeap( heap
, entry
));
565 /***********************************************************************
566 * Global/local heap functions
567 ***********************************************************************/
569 #include "pshpack1.h"
581 #define MAGIC_LOCAL_USED 0x5342
582 /* align the storage needed for the HLOCAL on an 8-byte boundary thus
583 * LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with
584 * size = 8*k, where k=1,2,3,... allocs exactly the given size.
585 * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
586 * the output jpeg's > 1 MB if not */
587 #define HLOCAL_STORAGE (sizeof(HLOCAL) * 2)
589 static inline struct local_header
*get_header( HLOCAL hmem
)
591 return (struct local_header
*)((char *)hmem
- 2);
594 static inline HLOCAL
get_handle( struct local_header
*header
)
599 static inline BOOL
is_pointer( HLOCAL hmem
)
601 return !((ULONG_PTR
)hmem
& 2);
604 /***********************************************************************
605 * GlobalAlloc (kernelbase.@)
607 HGLOBAL WINAPI DECLSPEC_HOTPATCH
GlobalAlloc( UINT flags
, SIZE_T size
)
609 /* mask out obsolete flags */
610 flags
&= ~(GMEM_NOCOMPACT
| GMEM_NOT_BANKED
| GMEM_NOTIFY
);
612 /* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */
613 if (!(flags
& GMEM_MOVEABLE
) && !size
) size
= 1;
615 return LocalAlloc( flags
, size
);
619 /***********************************************************************
620 * GlobalFree (kernelbase.@)
622 HGLOBAL WINAPI DECLSPEC_HOTPATCH
GlobalFree( HLOCAL hmem
)
624 return LocalFree( hmem
);
628 /***********************************************************************
629 * LocalAlloc (kernelbase.@)
631 HLOCAL WINAPI DECLSPEC_HOTPATCH
LocalAlloc( UINT flags
, SIZE_T size
)
633 struct local_header
*header
;
634 DWORD heap_flags
= 0;
637 if (flags
& LMEM_ZEROINIT
) heap_flags
= HEAP_ZERO_MEMORY
;
639 if (!(flags
& LMEM_MOVEABLE
)) /* pointer */
641 ptr
= HeapAlloc( GetProcessHeap(), heap_flags
, size
);
642 TRACE( "(flags=%04x) returning %p\n", flags
, ptr
);
646 if (size
> INT_MAX
- HLOCAL_STORAGE
)
648 SetLastError( ERROR_OUTOFMEMORY
);
651 if (!(header
= HeapAlloc( GetProcessHeap(), 0, sizeof(*header
) ))) return 0;
653 header
->magic
= MAGIC_LOCAL_USED
;
654 header
->flags
= flags
>> 8;
659 if (!(ptr
= HeapAlloc(GetProcessHeap(), heap_flags
, size
+ HLOCAL_STORAGE
)))
661 HeapFree( GetProcessHeap(), 0, header
);
664 *(HLOCAL
*)ptr
= get_handle( header
);
665 header
->ptr
= (char *)ptr
+ HLOCAL_STORAGE
;
667 else header
->ptr
= NULL
;
669 TRACE( "(flags=%04x) returning handle %p pointer %p\n",
670 flags
, get_handle( header
), header
->ptr
);
671 return get_handle( header
);
675 /***********************************************************************
676 * LocalFree (kernelbase.@)
678 HLOCAL WINAPI DECLSPEC_HOTPATCH
LocalFree( HLOCAL hmem
)
680 struct local_header
*header
;
683 RtlLockHeap( GetProcessHeap() );
687 if (is_pointer(hmem
)) /* POINTER */
689 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE
, hmem
))
691 SetLastError( ERROR_INVALID_HANDLE
);
697 header
= get_header( hmem
);
698 if (header
->magic
== MAGIC_LOCAL_USED
)
700 header
->magic
= 0xdead;
703 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE
,
704 (char *)header
->ptr
- HLOCAL_STORAGE
))
707 if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE
, header
)) ret
= hmem
;
711 WARN( "invalid handle %p (magic: 0x%04x)\n", hmem
, header
->magic
);
712 SetLastError( ERROR_INVALID_HANDLE
);
719 WARN( "invalid handle %p\n", hmem
);
720 SetLastError( ERROR_INVALID_HANDLE
);
724 RtlUnlockHeap( GetProcessHeap() );
729 /***********************************************************************
730 * LocalLock (kernelbase.@)
732 LPVOID WINAPI DECLSPEC_HOTPATCH
LocalLock( HLOCAL hmem
)
736 if (is_pointer( hmem
))
740 volatile char *p
= hmem
;
751 RtlLockHeap( GetProcessHeap() );
754 struct local_header
*header
= get_header( hmem
);
755 if (header
->magic
== MAGIC_LOCAL_USED
)
758 if (!header
->ptr
) SetLastError( ERROR_DISCARDED
);
759 else if (header
->lock
< LMEM_LOCKCOUNT
) header
->lock
++;
763 WARN( "invalid handle %p (magic: 0x%04x)\n", hmem
, header
->magic
);
764 SetLastError( ERROR_INVALID_HANDLE
);
769 WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem
);
770 SetLastError( ERROR_INVALID_HANDLE
);
773 RtlUnlockHeap( GetProcessHeap() );
778 /***********************************************************************
779 * LocalReAlloc (kernelbase.@)
781 HLOCAL WINAPI DECLSPEC_HOTPATCH
LocalReAlloc( HLOCAL hmem
, SIZE_T size
, UINT flags
)
783 struct local_header
*header
;
786 DWORD heap_flags
= (flags
& LMEM_ZEROINIT
) ? HEAP_ZERO_MEMORY
: 0;
788 RtlLockHeap( GetProcessHeap() );
789 if (flags
& LMEM_MODIFY
) /* modify flags */
791 if (is_pointer( hmem
) && (flags
& LMEM_MOVEABLE
))
793 /* make a fixed block moveable
794 * actually only NT is able to do this. But it's soo simple
798 WARN( "null handle\n");
799 SetLastError( ERROR_NOACCESS
);
803 size
= RtlSizeHeap( GetProcessHeap(), 0, hmem
);
804 ret
= LocalAlloc( flags
, size
);
805 ptr
= LocalLock( ret
);
806 memcpy( ptr
, hmem
, size
);
811 else if (!is_pointer( hmem
) && (flags
& LMEM_DISCARDABLE
))
813 /* change the flags to make our block "discardable" */
814 header
= get_header( hmem
);
815 header
->flags
|= LMEM_DISCARDABLE
>> 8;
818 else SetLastError( ERROR_INVALID_PARAMETER
);
822 if (is_pointer( hmem
))
824 /* reallocate fixed memory */
825 if (!(flags
& LMEM_MOVEABLE
)) heap_flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
826 ret
= HeapReAlloc( GetProcessHeap(), heap_flags
, hmem
, size
);
830 /* reallocate a moveable block */
831 header
= get_header( hmem
);
834 if (size
<= INT_MAX
- HLOCAL_STORAGE
)
838 if ((ptr
= HeapReAlloc( GetProcessHeap(), heap_flags
,
839 (char *)header
->ptr
- HLOCAL_STORAGE
,
840 size
+ HLOCAL_STORAGE
)))
842 header
->ptr
= (char *)ptr
+ HLOCAL_STORAGE
;
848 if ((ptr
= HeapAlloc( GetProcessHeap(), heap_flags
, size
+ HLOCAL_STORAGE
)))
850 *(HLOCAL
*)ptr
= hmem
;
851 header
->ptr
= (char *)ptr
+ HLOCAL_STORAGE
;
856 else SetLastError( ERROR_OUTOFMEMORY
);
860 if (header
->lock
== 0)
864 HeapFree( GetProcessHeap(), 0, (char *)header
->ptr
- HLOCAL_STORAGE
);
869 else WARN( "not freeing memory associated with locked handle\n" );
873 RtlUnlockHeap( GetProcessHeap() );
878 /***********************************************************************
879 * LocalUnlock (kernelbase.@)
881 BOOL WINAPI DECLSPEC_HOTPATCH
LocalUnlock( HLOCAL hmem
)
885 if (is_pointer( hmem
))
887 SetLastError( ERROR_NOT_LOCKED
);
891 RtlLockHeap( GetProcessHeap() );
894 struct local_header
*header
= get_header( hmem
);
895 if (header
->magic
== MAGIC_LOCAL_USED
)
900 ret
= (header
->lock
!= 0);
901 if (!ret
) SetLastError( NO_ERROR
);
905 WARN( "%p not locked\n", hmem
);
906 SetLastError( ERROR_NOT_LOCKED
);
911 WARN( "invalid handle %p (Magic: 0x%04x)\n", hmem
, header
->magic
);
912 SetLastError( ERROR_INVALID_HANDLE
);
917 WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem
);
918 SetLastError( ERROR_INVALID_PARAMETER
);
921 RtlUnlockHeap( GetProcessHeap() );
926 /***********************************************************************
927 * Memory resource functions
928 ***********************************************************************/
931 /***********************************************************************
932 * CreateMemoryResourceNotification (kernelbase.@)
934 HANDLE WINAPI DECLSPEC_HOTPATCH
CreateMemoryResourceNotification( MEMORY_RESOURCE_NOTIFICATION_TYPE type
)
937 UNICODE_STRING nameW
;
938 OBJECT_ATTRIBUTES attr
;
942 case LowMemoryResourceNotification
:
943 RtlInitUnicodeString( &nameW
, L
"\\KernelObjects\\LowMemoryCondition" );
945 case HighMemoryResourceNotification
:
946 RtlInitUnicodeString( &nameW
, L
"\\KernelObjects\\HighMemoryCondition" );
949 SetLastError( ERROR_INVALID_PARAMETER
);
953 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
954 if (!set_ntstatus( NtOpenEvent( &ret
, EVENT_ALL_ACCESS
, &attr
))) return 0;
958 /***********************************************************************
959 * QueryMemoryResourceNotification (kernelbase.@)
961 BOOL WINAPI DECLSPEC_HOTPATCH
QueryMemoryResourceNotification( HANDLE handle
, BOOL
*state
)
963 switch (WaitForSingleObject( handle
, 0 ))
972 SetLastError( ERROR_INVALID_PARAMETER
);
977 /***********************************************************************
978 * Physical memory functions
979 ***********************************************************************/
982 /***********************************************************************
983 * AllocateUserPhysicalPages (kernelbase.@)
985 BOOL WINAPI DECLSPEC_HOTPATCH
AllocateUserPhysicalPages( HANDLE process
, ULONG_PTR
*pages
,
986 ULONG_PTR
*userarray
)
988 FIXME( "stub: %p %p %p\n", process
, pages
, userarray
);
989 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
994 /***********************************************************************
995 * FreeUserPhysicalPages (kernelbase.@)
997 BOOL WINAPI DECLSPEC_HOTPATCH
FreeUserPhysicalPages( HANDLE process
, ULONG_PTR
*pages
,
998 ULONG_PTR
*userarray
)
1000 FIXME( "stub: %p %p %p\n", process
, pages
, userarray
);
1002 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1007 /***********************************************************************
1008 * GetPhysicallyInstalledSystemMemory (kernelbase.@)
1010 BOOL WINAPI DECLSPEC_HOTPATCH
GetPhysicallyInstalledSystemMemory( ULONGLONG
*memory
)
1012 MEMORYSTATUSEX status
;
1016 SetLastError( ERROR_INVALID_PARAMETER
);
1019 status
.dwLength
= sizeof(status
);
1020 GlobalMemoryStatusEx( &status
);
1021 *memory
= status
.ullTotalPhys
/ 1024;
1026 /***********************************************************************
1027 * GlobalMemoryStatusEx (kernelbase.@)
1029 BOOL WINAPI DECLSPEC_HOTPATCH
GlobalMemoryStatusEx( MEMORYSTATUSEX
*status
)
1031 static MEMORYSTATUSEX cached_status
;
1032 static DWORD last_check
;
1033 SYSTEM_BASIC_INFORMATION basic_info
;
1034 SYSTEM_PERFORMANCE_INFORMATION perf_info
;
1036 if (status
->dwLength
!= sizeof(*status
))
1038 SetLastError( ERROR_INVALID_PARAMETER
);
1041 if ((NtGetTickCount() - last_check
) < 1000)
1043 *status
= cached_status
;
1046 last_check
= NtGetTickCount();
1048 if (!set_ntstatus( NtQuerySystemInformation( SystemBasicInformation
,
1049 &basic_info
, sizeof(basic_info
), NULL
)) ||
1050 !set_ntstatus( NtQuerySystemInformation( SystemPerformanceInformation
,
1051 &perf_info
, sizeof(perf_info
), NULL
)))
1054 status
->dwMemoryLoad
= 0;
1055 status
->ullTotalPhys
= perf_info
.TotalCommitLimit
;
1056 status
->ullAvailPhys
= perf_info
.AvailablePages
;
1057 status
->ullTotalPageFile
= perf_info
.TotalCommitLimit
+ 1; /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */
1058 status
->ullAvailPageFile
= status
->ullTotalPageFile
- perf_info
.TotalCommittedPages
;
1059 status
->ullTotalVirtual
= (ULONG_PTR
)basic_info
.HighestUserAddress
- (ULONG_PTR
)basic_info
.LowestUserAddress
;
1060 status
->ullAvailVirtual
= status
->ullTotalVirtual
- 64 * 1024; /* FIXME */
1061 status
->ullAvailExtendedVirtual
= 0;
1063 status
->ullTotalPhys
*= basic_info
.PageSize
;
1064 status
->ullAvailPhys
*= basic_info
.PageSize
;
1065 status
->ullTotalPageFile
*= basic_info
.PageSize
;
1066 status
->ullAvailPageFile
*= basic_info
.PageSize
;
1068 if (status
->ullTotalPhys
)
1069 status
->dwMemoryLoad
= (status
->ullTotalPhys
- status
->ullAvailPhys
) / (status
->ullTotalPhys
/ 100);
1071 TRACE_(virtual)( "MemoryLoad %d, TotalPhys %s, AvailPhys %s, TotalPageFile %s,"
1072 "AvailPageFile %s, TotalVirtual %s, AvailVirtual %s\n",
1073 status
->dwMemoryLoad
, wine_dbgstr_longlong(status
->ullTotalPhys
),
1074 wine_dbgstr_longlong(status
->ullAvailPhys
), wine_dbgstr_longlong(status
->ullTotalPageFile
),
1075 wine_dbgstr_longlong(status
->ullAvailPageFile
), wine_dbgstr_longlong(status
->ullTotalVirtual
),
1076 wine_dbgstr_longlong(status
->ullAvailVirtual
) );
1078 cached_status
= *status
;
1083 /***********************************************************************
1084 * MapUserPhysicalPages (kernelbase.@)
1086 BOOL WINAPI DECLSPEC_HOTPATCH
MapUserPhysicalPages( void *addr
, ULONG_PTR page_count
, ULONG_PTR
*pages
)
1088 FIXME( "stub: %p %lu %p\n", addr
, page_count
, pages
);
1090 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1095 /***********************************************************************
1097 ***********************************************************************/
1100 /***********************************************************************
1101 * AllocateUserPhysicalPagesNuma (kernelbase.@)
1103 BOOL WINAPI DECLSPEC_HOTPATCH
AllocateUserPhysicalPagesNuma( HANDLE process
, ULONG_PTR
*pages
,
1104 ULONG_PTR
*userarray
, DWORD node
)
1106 if (node
) FIXME( "Ignoring preferred node %u\n", node
);
1107 return AllocateUserPhysicalPages( process
, pages
, userarray
);
1111 /***********************************************************************
1112 * CreateFileMappingNumaW (kernelbase.@)
1114 HANDLE WINAPI DECLSPEC_HOTPATCH
CreateFileMappingNumaW( HANDLE file
, LPSECURITY_ATTRIBUTES sa
,
1115 DWORD protect
, DWORD size_high
, DWORD size_low
,
1116 LPCWSTR name
, DWORD node
)
1118 if (node
) FIXME( "Ignoring preferred node %u\n", node
);
1119 return CreateFileMappingW( file
, sa
, protect
, size_high
, size_low
, name
);
1123 /***********************************************************************
1124 * GetLogicalProcessorInformation (kernelbase.@)
1126 BOOL WINAPI DECLSPEC_HOTPATCH
GetLogicalProcessorInformation( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
*buffer
,
1133 SetLastError( ERROR_INVALID_PARAMETER
);
1136 status
= NtQuerySystemInformation( SystemLogicalProcessorInformation
, buffer
, *len
, len
);
1137 if (status
== STATUS_INFO_LENGTH_MISMATCH
) status
= STATUS_BUFFER_TOO_SMALL
;
1138 return set_ntstatus( status
);
1142 /***********************************************************************
1143 * GetLogicalProcessorInformationEx (kernelbase.@)
1145 BOOL WINAPI DECLSPEC_HOTPATCH
GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP relationship
,
1146 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*buffer
, DWORD
*len
)
1152 SetLastError( ERROR_INVALID_PARAMETER
);
1155 status
= NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx
, &relationship
,
1156 sizeof(relationship
), buffer
, *len
, len
);
1157 if (status
== STATUS_INFO_LENGTH_MISMATCH
) status
= STATUS_BUFFER_TOO_SMALL
;
1158 return set_ntstatus( status
);
1162 /***********************************************************************
1163 * GetSystemCpuSetInformation (kernelbase.@)
1165 BOOL WINAPI
GetSystemCpuSetInformation(SYSTEM_CPU_SET_INFORMATION
*info
, ULONG buffer_length
, ULONG
*return_length
,
1166 HANDLE process
, ULONG flags
)
1169 FIXME("Unsupported flags %#x.\n", flags
);
1173 return set_ntstatus( NtQuerySystemInformationEx( SystemCpuSetInformation
, &process
, sizeof(process
), info
,
1174 buffer_length
, return_length
));
1178 /***********************************************************************
1179 * SetThreadSelectedCpuSets (kernelbase.@)
1181 BOOL WINAPI
SetThreadSelectedCpuSets(HANDLE thread
, const ULONG
*cpu_set_ids
, ULONG count
)
1183 FIXME( "thread %p, cpu_set_ids %p, count %u stub.\n", thread
, cpu_set_ids
, count
);
1189 /**********************************************************************
1190 * GetNumaHighestNodeNumber (kernelbase.@)
1192 BOOL WINAPI DECLSPEC_HOTPATCH
GetNumaHighestNodeNumber( ULONG
*node
)
1194 FIXME( "semi-stub: %p\n", node
);
1200 /**********************************************************************
1201 * GetNumaNodeProcessorMaskEx (kernelbase.@)
1203 BOOL WINAPI DECLSPEC_HOTPATCH
GetNumaNodeProcessorMaskEx( USHORT node
, GROUP_AFFINITY
*mask
)
1205 FIXME( "stub: %hu %p\n", node
, mask
);
1206 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1211 /***********************************************************************
1212 * GetNumaProximityNodeEx (kernelbase.@)
1214 BOOL WINAPI DECLSPEC_HOTPATCH
GetNumaProximityNodeEx( ULONG proximity_id
, USHORT
*node
)
1216 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1221 /***********************************************************************
1222 * MapViewOfFileExNuma (kernelbase.@)
1224 LPVOID WINAPI DECLSPEC_HOTPATCH
MapViewOfFileExNuma( HANDLE handle
, DWORD access
, DWORD offset_high
,
1225 DWORD offset_low
, SIZE_T count
, LPVOID addr
,
1228 if (node
) FIXME( "Ignoring preferred node %u\n", node
);
1229 return MapViewOfFileEx( handle
, access
, offset_high
, offset_low
, count
, addr
);
1233 /***********************************************************************
1234 * VirtualAllocExNuma (kernelbase.@)
1236 LPVOID WINAPI DECLSPEC_HOTPATCH
VirtualAllocExNuma( HANDLE process
, void *addr
, SIZE_T size
,
1237 DWORD type
, DWORD protect
, DWORD node
)
1239 if (node
) FIXME( "Ignoring preferred node %u\n", node
);
1240 return VirtualAllocEx( process
, addr
, size
, type
, protect
);
1244 /***********************************************************************
1246 ***********************************************************************/
1249 #if defined(__i386__) || defined(__x86_64__)
1250 /***********************************************************************
1251 * GetEnabledXStateFeatures (kernelbase.@)
1253 DWORD64 WINAPI
GetEnabledXStateFeatures(void)
1256 return RtlGetEnabledExtendedFeatures( ~(ULONG64
)0 );
1260 /***********************************************************************
1261 * InitializeContext2 (kernelbase.@)
1263 BOOL WINAPI
InitializeContext2( void *buffer
, DWORD context_flags
, CONTEXT
**context
, DWORD
*length
,
1264 ULONG64 compaction_mask
)
1269 TRACE( "buffer %p, context_flags %#x, context %p, ret_length %p, compaction_mask %s.\n",
1270 buffer
, context_flags
, context
, length
, wine_dbgstr_longlong(compaction_mask
) );
1272 orig_length
= *length
;
1274 if ((status
= RtlGetExtendedContextLength2( context_flags
, length
, compaction_mask
)))
1276 if (status
== STATUS_NOT_SUPPORTED
&& context_flags
& 0x40)
1278 context_flags
&= ~0x40;
1279 status
= RtlGetExtendedContextLength2( context_flags
, length
, compaction_mask
);
1283 return set_ntstatus( status
);
1286 if (!buffer
|| orig_length
< *length
)
1288 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1292 if ((status
= RtlInitializeExtendedContext2( buffer
, context_flags
, (CONTEXT_EX
**)context
, compaction_mask
)))
1293 return set_ntstatus( status
);
1295 *context
= (CONTEXT
*)((BYTE
*)*context
+ (*(CONTEXT_EX
**)context
)->Legacy
.Offset
);
1300 /***********************************************************************
1301 * InitializeContext (kernelbase.@)
1303 BOOL WINAPI
InitializeContext( void *buffer
, DWORD context_flags
, CONTEXT
**context
, DWORD
*length
)
1305 return InitializeContext2( buffer
, context_flags
, context
, length
, ~(ULONG64
)0 );
1308 /***********************************************************************
1309 * CopyContext (kernelbase.@)
1311 BOOL WINAPI
CopyContext( CONTEXT
*dst
, DWORD context_flags
, CONTEXT
*src
)
1313 DWORD context_size
, arch_flag
, flags_offset
, dst_flags
, src_flags
;
1314 static const DWORD arch_mask
= 0x110000;
1318 TRACE("dst %p, context_flags %#x, src %p.\n", dst
, context_flags
, src
);
1320 if (context_flags
& 0x40 && !RtlGetEnabledExtendedFeatures( ~(ULONG64
)0 ))
1322 SetLastError(ERROR_NOT_SUPPORTED
);
1326 arch_flag
= context_flags
& arch_mask
;
1330 case 0x10000: context_size
= 0x2cc; flags_offset
= 0; break;
1331 case 0x100000: context_size
= 0x4d0; flags_offset
= 0x30; break;
1333 SetLastError( ERROR_INVALID_PARAMETER
);
1339 dst_flags
= *(DWORD
*)(d
+ flags_offset
);
1340 src_flags
= *(DWORD
*)(s
+ flags_offset
);
1342 if ((dst_flags
& arch_mask
) != arch_flag
1343 || (src_flags
& arch_mask
) != arch_flag
)
1345 SetLastError( ERROR_INVALID_PARAMETER
);
1349 context_flags
&= src_flags
;
1351 if (context_flags
& ~dst_flags
& 0x40)
1353 SetLastError(ERROR_MORE_DATA
);
1357 if ((status
= RtlCopyExtendedContext( (CONTEXT_EX
*)(d
+ context_size
), context_flags
,
1358 (CONTEXT_EX
*)(s
+ context_size
) )))
1359 return set_ntstatus( status
);
1366 #if defined(__x86_64__)
1367 /***********************************************************************
1368 * LocateXStateFeature (kernelbase.@)
1370 void * WINAPI
LocateXStateFeature( CONTEXT
*context
, DWORD feature_id
, DWORD
*length
)
1372 if (!(context
->ContextFlags
& CONTEXT_AMD64
))
1375 if (feature_id
>= 2)
1376 return ((context
->ContextFlags
& CONTEXT_XSTATE
) == CONTEXT_XSTATE
)
1377 ? RtlLocateExtendedFeature( (CONTEXT_EX
*)(context
+ 1), feature_id
, length
) : NULL
;
1379 if (feature_id
== 1)
1382 *length
= sizeof(M128A
) * 16;
1384 return &context
->u
.FltSave
.XmmRegisters
;
1388 *length
= offsetof(XSAVE_FORMAT
, XmmRegisters
);
1390 return &context
->u
.FltSave
;
1393 /***********************************************************************
1394 * SetXStateFeaturesMask (kernelbase.@)
1396 BOOL WINAPI
SetXStateFeaturesMask( CONTEXT
*context
, DWORD64 feature_mask
)
1398 if (!(context
->ContextFlags
& CONTEXT_AMD64
))
1401 if (feature_mask
& 0x3)
1402 context
->ContextFlags
|= CONTEXT_FLOATING_POINT
;
1404 if ((context
->ContextFlags
& CONTEXT_XSTATE
) != CONTEXT_XSTATE
)
1405 return !(feature_mask
& ~(DWORD64
)3);
1407 RtlSetExtendedFeaturesMask( (CONTEXT_EX
*)(context
+ 1), feature_mask
);
1411 /***********************************************************************
1412 * GetXStateFeaturesMask (kernelbase.@)
1414 BOOL WINAPI
GetXStateFeaturesMask( CONTEXT
*context
, DWORD64
*feature_mask
)
1416 if (!(context
->ContextFlags
& CONTEXT_AMD64
))
1419 *feature_mask
= (context
->ContextFlags
& CONTEXT_FLOATING_POINT
) == CONTEXT_FLOATING_POINT
1422 if ((context
->ContextFlags
& CONTEXT_XSTATE
) == CONTEXT_XSTATE
)
1423 *feature_mask
|= RtlGetExtendedFeaturesMask( (CONTEXT_EX
*)(context
+ 1) );
1427 #elif defined(__i386__)
1428 /***********************************************************************
1429 * LocateXStateFeature (kernelbase.@)
1431 void * WINAPI
LocateXStateFeature( CONTEXT
*context
, DWORD feature_id
, DWORD
*length
)
1433 if (!(context
->ContextFlags
& CONTEXT_X86
))
1436 if (feature_id
>= 2)
1437 return ((context
->ContextFlags
& CONTEXT_XSTATE
) == CONTEXT_XSTATE
)
1438 ? RtlLocateExtendedFeature( (CONTEXT_EX
*)(context
+ 1), feature_id
, length
) : NULL
;
1440 if (feature_id
== 1)
1443 *length
= sizeof(M128A
) * 8;
1445 return (BYTE
*)&context
->ExtendedRegisters
+ offsetof(XSAVE_FORMAT
, XmmRegisters
);
1449 *length
= offsetof(XSAVE_FORMAT
, XmmRegisters
);
1451 return &context
->ExtendedRegisters
;
1454 /***********************************************************************
1455 * SetXStateFeaturesMask (kernelbase.@)
1457 BOOL WINAPI
SetXStateFeaturesMask( CONTEXT
*context
, DWORD64 feature_mask
)
1459 if (!(context
->ContextFlags
& CONTEXT_X86
))
1462 if (feature_mask
& 0x3)
1463 context
->ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
1465 if ((context
->ContextFlags
& CONTEXT_XSTATE
) != CONTEXT_XSTATE
)
1466 return !(feature_mask
& ~(DWORD64
)3);
1468 RtlSetExtendedFeaturesMask( (CONTEXT_EX
*)(context
+ 1), feature_mask
);
1472 /***********************************************************************
1473 * GetXStateFeaturesMask (kernelbase.@)
1475 BOOL WINAPI
GetXStateFeaturesMask( CONTEXT
*context
, DWORD64
*feature_mask
)
1477 if (!(context
->ContextFlags
& CONTEXT_X86
))
1480 *feature_mask
= (context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) == CONTEXT_EXTENDED_REGISTERS
1483 if ((context
->ContextFlags
& CONTEXT_XSTATE
) == CONTEXT_XSTATE
)
1484 *feature_mask
|= RtlGetExtendedFeaturesMask( (CONTEXT_EX
*)(context
+ 1) );
1490 /***********************************************************************
1491 * Firmware functions
1492 ***********************************************************************/
1495 /***********************************************************************
1496 * EnumSystemFirmwareTable (kernelbase.@)
1498 UINT WINAPI
EnumSystemFirmwareTables( DWORD provider
, void *buffer
, DWORD size
)
1500 FIXME( "(0x%08x, %p, %d)\n", provider
, buffer
, size
);
1505 /***********************************************************************
1506 * GetSystemFirmwareTable (kernelbase.@)
1508 UINT WINAPI
GetSystemFirmwareTable( DWORD provider
, DWORD id
, void *buffer
, DWORD size
)
1510 SYSTEM_FIRMWARE_TABLE_INFORMATION
*info
;
1511 ULONG buffer_size
= offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
) + size
;
1513 TRACE( "(0x%08x, 0x%08x, %p, %d)\n", provider
, id
, buffer
, size
);
1515 if (!(info
= RtlAllocateHeap( GetProcessHeap(), 0, buffer_size
)))
1517 SetLastError( ERROR_OUTOFMEMORY
);
1521 info
->ProviderSignature
= provider
;
1522 info
->Action
= SystemFirmwareTable_Get
;
1525 set_ntstatus( NtQuerySystemInformation( SystemFirmwareTableInformation
,
1526 info
, buffer_size
, &buffer_size
));
1527 buffer_size
-= offsetof( SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
);
1528 if (buffer_size
<= size
) memcpy( buffer
, info
->TableBuffer
, buffer_size
);
1530 HeapFree( GetProcessHeap(), 0, info
);