Index: reactos/dll/ntdll/def/ntdll.spec =================================================================== --- reactos/dll/ntdll/def/ntdll.spec (revision 73408) +++ reactos/dll/ntdll/def/ntdll.spec (working copy) @@ -776,8 +776,8 @@ 771 stdcall RtlMultiAppendUnicodeStringBuffer(ptr long ptr) 772 stdcall RtlMultiByteToUnicodeN(ptr long ptr ptr long) 773 stdcall RtlMultiByteToUnicodeSize(ptr str long) -# RtlMultipleAllocateHeap -# RtlMultipleFreeHeap +774 stdcall RtlMultipleAllocateHeap(ptr long long long ptr) +775 stdcall RtlMultipleFreeHeap(ptr long long ptr) 776 stdcall RtlNewInstanceSecurityObject(long long ptr ptr ptr ptr ptr long ptr ptr) 777 stdcall RtlNewSecurityGrantedAccess(long ptr ptr ptr ptr ptr) 778 stdcall RtlNewSecurityObject(ptr ptr ptr long ptr ptr) Index: reactos/sdk/include/ndk/rtlfuncs.h =================================================================== --- reactos/sdk/include/ndk/rtlfuncs.h (revision 73408) +++ reactos/sdk/include/ndk/rtlfuncs.h (working copy) @@ -972,9 +972,9 @@ _Must_inspect_result_ NTSYSAPI -NTSTATUS +ULONG NTAPI -RtlMultipleAllocateHeap ( +RtlMultipleAllocateHeap( _In_ HANDLE HeapHandle, _In_ ULONG Flags, _In_ SIZE_T Size, @@ -983,9 +983,9 @@ ); NTSYSAPI -NTSTATUS +ULONG NTAPI -RtlMultipleFreeHeap ( +RtlMultipleFreeHeap( _In_ HANDLE HeapHandle, _In_ ULONG Flags, _In_ ULONG Count, Index: reactos/sdk/lib/rtl/heap.c =================================================================== --- reactos/sdk/lib/rtl/heap.c (revision 73408) +++ reactos/sdk/lib/rtl/heap.c (working copy) @@ -4,6 +4,7 @@ * FILE: lib/rtl/heap.c * PURPOSE: RTL Heap backend allocator * PROGRAMMERS: Copyright 2010 Aleksey Bragin + * Copyright 2016 Katayama Hirofumi MZ */ /* Useful references: @@ -3955,7 +3956,8 @@ return STATUS_UNSUCCESSFUL; } -NTSTATUS +/* @implemented */ +ULONG NTAPI RtlMultipleAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, @@ -3963,11 +3965,36 @@ IN ULONG Count, OUT PVOID *Array) { - UNIMPLEMENTED; - return 0; + ULONG Index; + EXCEPTION_RECORD ExceptionRecord; + + for (Index = 0; Index < Count; ++Index) + { + Array[Index] = RtlAllocateHeap(HeapHandle, Flags, Size); + if (Array[Index] == NULL) + { + /* ERROR_NOT_ENOUGH_MEMORY */ + RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_NO_MEMORY); + + if (Flags & HEAP_GENERATE_EXCEPTIONS) + { + ExceptionRecord.ExceptionCode = STATUS_NO_MEMORY; + ExceptionRecord.ExceptionRecord = NULL; + ExceptionRecord.NumberParameters = 0; + ExceptionRecord.ExceptionFlags = 0; + + RtlRaiseException(&ExceptionRecord); + } + + break; + } + } + + return Index; } -NTSTATUS +/* @implemented */ +ULONG NTAPI RtlMultipleFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, @@ -3974,8 +4001,46 @@ IN ULONG Count, OUT PVOID *Array) { - UNIMPLEMENTED; - return 0; + ULONG Index; + EXCEPTION_RECORD ExceptionRecord; + + Flags &= ~HEAP_GENERATE_EXCEPTIONS; + + for (Index = 0; Index < Count; ++Index) + { + if (Array == NULL) + { + ExceptionRecord.ExceptionCode = STATUS_ACCESS_VIOLATION; + ExceptionRecord.ExceptionRecord = NULL; + ExceptionRecord.NumberParameters = 0; + ExceptionRecord.ExceptionFlags = 0; + + RtlRaiseException(&ExceptionRecord); + } + if (Array[Index] == NULL) + { + continue; + } + _SEH2_TRY + { + if (!RtlFreeHeap(HeapHandle, Flags, Array[Index])) + { + /* ERROR_INVALID_PARAMETER */ + RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER); + + break; + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* ERROR_INVALID_PARAMETER */ + RtlSetLastWin32ErrorAndNtStatusFromNtStatus(STATUS_INVALID_PARAMETER); + break; + } + _SEH2_END; + } + + return Index; } /* EOF */ Index: rostests/apitests/kernel32/CMakeLists.txt =================================================================== --- rostests/apitests/kernel32/CMakeLists.txt (revision 73408) +++ rostests/apitests/kernel32/CMakeLists.txt (working copy) @@ -17,7 +17,8 @@ TunnelCache.c WideCharToMultiByte.c testlist.c - Mailslot.c) + Mailslot.c + MultiHeap.c) add_executable(kernel32_apitest ${SOURCE}) target_link_libraries(kernel32_apitest wine ${PSEH_LIB}) Index: rostests/apitests/kernel32/MultiHeap.c =================================================================== --- rostests/apitests/kernel32/MultiHeap.c (nonexistent) +++ rostests/apitests/kernel32/MultiHeap.c (working copy) @@ -0,0 +1,324 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory + * PURPOSE: Test for RtlMultipleAllocateHeap and RtlMultipleFreeHeap + * PROGRAMMER: Katayama Hirofumi MZ + */ + +#include +#include + +// #define HEAP_NO_SERIALIZE 0x00000001 +// #define HEAP_GROWABLE 0x00000002 +// #define HEAP_GENERATE_EXCEPTIONS 0x00000004 +// #define HEAP_ZERO_MEMORY 0x00000008 +// #define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 +// #define HEAP_TAIL_CHECKING_ENABLED 0x00000020 +// #define HEAP_FREE_CHECKING_ENABLED 0x00000040 +// #define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 +// #define HEAP_CREATE_ALIGN_16 0x00010000 +// #define HEAP_CREATE_ENABLE_TRACING 0x00020000 +// #define HEAP_CREATE_ENABLE_EXECUTE 0x00040000 + +// RtlMultipleAllocateHeap +typedef ULONG (NTAPI *RTLMULTIPLEALLOCATEHEAP)( + IN PVOID HeapHandle, + IN ULONG Flags, + IN SIZE_T Size, + IN ULONG Count, + OUT PVOID *Array); + +// RtlMultipleFreeHeap +typedef ULONG (NTAPI *RTLMULTIPLEFREEHEAP)( + IN PVOID HeapHandle, + IN ULONG Flags, + IN ULONG Count, + OUT PVOID *Array); + +HINSTANCE g_ntdll; +RTLMULTIPLEALLOCATEHEAP g_alloc; +RTLMULTIPLEFREEHEAP g_free; + +#define TEST_ALLOC(ret_expected,err_expected,threw_excepted,HeapHandle,Flags,Size,Count,Array) \ + threw = 0; \ + SetLastError(-1); \ + _SEH2_TRY { \ + ret = g_alloc((HeapHandle), (Flags), (Size), (Count), (Array)); \ + err = GetLastError(); \ + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \ + threw = _SEH2_GetExceptionCode(); \ + } \ + _SEH2_END \ + ok((ret) == (ret_expected), "ret excepted %d, but %d\n", (ret_expected), (ret)); \ + ok((err) == (err_expected), "err excepted %d, but %d\n", (err_expected), (err)); \ + ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", (threw_excepted), (threw)); + +#define TEST_ALLOC_NO_RET(err_expected,threw_excepted,HeapHandle,Flags,Size,Count,Array) \ + threw = 0; \ + SetLastError(-1); \ + _SEH2_TRY { \ + ret = g_alloc((HeapHandle), (Flags), (Size), (Count), (Array)); \ + err = GetLastError(); \ + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \ + threw = _SEH2_GetExceptionCode(); \ + } \ + _SEH2_END \ + ok((err) == (err_expected), "err excepted %d, but %d", (err_expected), (err)); \ + ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", (threw_excepted), (threw)); + +#define TEST_FREE(ret_expected,err_expected,threw_excepted,HeapHandle,Flags,Count,Array) \ + threw = 0; \ + SetLastError(-1); \ + _SEH2_TRY { \ + ret = g_free((HeapHandle), (Flags), (Count), (Array)); \ + err = GetLastError(); \ + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \ + threw = _SEH2_GetExceptionCode(); \ + } \ + _SEH2_END \ + ok((ret) == (ret_expected), "ret excepted %d, but %d\n", (ret_expected), (ret)); \ + ok((err) == (err_expected), "err excepted %d, but %d\n", (err_expected), (err)); \ + ok((threw) == (threw_excepted), "threw excepted %d, but %d\n", (threw_excepted), (threw)); + +#define ASSUME_ARRAY_ITEMS_ARE_NULL() \ + ok(Array[0] == NULL, "Array[0] is expected as NULL\n"); \ + ok(Array[1] == NULL, "Array[1] is expected as NULL\n"); \ + ok(Array[2] == NULL, "Array[2] is expected as NULL\n"); + +#define INT_EXPECTED(var,value) \ + ok((var) == (value), #var " expected %d, but %d\n", (value), (var)) + +void set_array(PVOID *array, PVOID p0, PVOID p1, PVOID p2) +{ + array[0] = p0; + array[1] = p1; + array[2] = p2; +} + +void MultiHeapAllocTest() +{ + INT ret, threw, err; + HANDLE HeapHandle = GetProcessHeap(); + PVOID Array[3] = {NULL, NULL, NULL}; + + // HeapHandle is NULL + TEST_ALLOC(0, -1, 0, NULL, 0, 0, 0, NULL); + TEST_ALLOC(0, -1, 0, NULL, 0, 0, 0, (HANDLE)1); + TEST_ALLOC(0, -1, 0xC0000005, NULL, 0, 0, 1, (HANDLE)1); + TEST_ALLOC(0, -1, 0, NULL, 0, 1, 0, (HANDLE)1); + TEST_ALLOC(0, -1, 0xC0000005, NULL, 0, 1, 1, (HANDLE)1); + + // HeapHandle is non-NULL and array is NULL + TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, NULL); + TEST_ALLOC(0, -1, 0xC0000005, HeapHandle, 0, 0, 1, NULL); + TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, NULL); + TEST_ALLOC(0, -1, 0xC0000005, HeapHandle, 0, 1, 1, NULL); + + // Array is non-NULL and contents are NULL + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, Array); + ASSUME_ARRAY_ITEMS_ARE_NULL(); + + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC(1, -1, 0, HeapHandle, 0, 0, 1, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] == NULL, "Array[1] is expected as NULL\n"); + ok(Array[2] == NULL, "Array[2] is expected as NULL\n"); + + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, Array); + ASSUME_ARRAY_ITEMS_ARE_NULL(); + + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC(1, -1, 0, HeapHandle, 0, 1, 1, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] == NULL, "Array[1] is expected as NULL\n"); + ok(Array[2] == NULL, "Array[2] is expected as NULL\n"); + + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC(2, -1, 0, HeapHandle, 0, 1, 2, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] != NULL, "Array[1] is expected as NULL\n"); + ok(Array[2] == NULL, "Array[2] is expected as NULL\n"); + + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC(3, -1, 0, HeapHandle, 0, 1, 3, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] != NULL, "Array[1] is expected as NULL\n"); + ok(Array[2] != NULL, "Array[2] is expected as NULL\n"); + + // Array is non-NULL and contents are invalid pointers + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_ALLOC(0, -1, 0, HeapHandle, 0, 0, 0, Array); + ok(Array[0] == (PVOID)1, "Array[0] is expected as 1\n"); + ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n"); + ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n"); + + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_ALLOC(1, -1, 0, HeapHandle, 0, 0, 1, Array); + ok(Array[0] != NULL, "Array[0] is expected as 1\n"); + ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n"); + ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n"); + + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_ALLOC(0, -1, 0, HeapHandle, 0, 1, 0, Array); + ok(Array[0] == (PVOID)1, "Array[0] is expected as 1\n"); + ok(Array[1] == (PVOID)2, "Array[1] is expected as 2\n"); + ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n"); + + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_ALLOC(1, -1, 0, HeapHandle, 0, 1, 1, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] == (PVOID)2, "Array[1] is expected as non-NULL\n"); + ok(Array[2] == (PVOID)3, "Array[2] is expected as NULL\n"); + + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_ALLOC(2, -1, 0, HeapHandle, 0, 1, 2, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n"); + ok(Array[2] == (PVOID)3, "Array[2] is expected as 3\n"); + + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_ALLOC(3, -1, 0, HeapHandle, 0, 1, 3, Array); + ok(Array[0] != NULL, "Array[0] is expected as non-NULL\n"); + ok(Array[1] != NULL, "Array[1] is expected as non-NULL\n"); + ok(Array[2] != NULL, "Array[2] is expected as non-NULL\n"); + + // Array is non-NULL and too large to allocate + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC_NO_RET(ERROR_NOT_ENOUGH_MEMORY, 0, HeapHandle, 0, 0x5FFFFFFF, 3, Array); + ok(ret != 3, "excepted not allocated"); + set_array(Array, NULL, NULL, NULL); + TEST_ALLOC_NO_RET(ERROR_NOT_ENOUGH_MEMORY, 0xC0000017, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 0x5FFFFFFF, 3, Array); + ok(ret != 3, "excepted not allocated"); +} + +void MultiHeapFreeTest() +{ + INT ret, threw, err; + HANDLE HeapHandle = GetProcessHeap(); + PVOID Array[3] = {NULL, NULL, NULL}; + + // HeapHandle is NULL + TEST_FREE(0, -1, 0, NULL, 0, 0, NULL); + TEST_FREE(0, -1, 0, NULL, 0, 0, (HANDLE)1); + TEST_FREE(0, -1, 0xC0000005, NULL, 0, 1, (HANDLE)1); + TEST_FREE(0, -1, 0xC0000005, NULL, 0, 2, (HANDLE)1); + TEST_FREE(0, -1, 0xC0000005, NULL, 0, 3, (HANDLE)1); + + // HeapHandle is non-NULL and array is NULL + TEST_FREE(0, -1, 0, HeapHandle, 0, 0, NULL); + TEST_FREE(0, -1, 0, HeapHandle, 0, 0, NULL); + TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 1, NULL); + TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 2, NULL); + TEST_FREE(0, -1, 0xC0000005, HeapHandle, 0, 3, NULL); + + // Array is non-NULL and contents are NULL + set_array(Array, NULL, NULL, NULL); + TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array); + set_array(Array, NULL, NULL, NULL); + TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array); + set_array(Array, NULL, NULL, NULL); + TEST_FREE(2, -1, 0, HeapHandle, 0, 2, Array); + set_array(Array, NULL, NULL, NULL); + TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array); + + // Array is non-NULL and contents are invalid pointers + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array); + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 1, Array); + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 2, Array); + set_array(Array, (PVOID)1, (PVOID)2, (PVOID)3); + TEST_FREE(0, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 3, Array); + + // Array is non-NULL and contents are 1 valid pointer and 2 NULLs + set_array(Array, NULL, NULL, NULL); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array); + + set_array(Array, NULL, NULL, NULL); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array); + + set_array(Array, NULL, NULL, NULL); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(2, -1, 0, HeapHandle, 0, 2, Array); + + set_array(Array, NULL, NULL, NULL); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array); + + // Array is non-NULL and contents are 1 valid pointer and 2 invalids + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(0, -1, 0, HeapHandle, 0, 0, Array); + + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, -1, 0, HeapHandle, 0, 1, Array); + + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 2, Array); + + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, 0, 3, Array); + + // Array is non-NULL and contents are 1 valid pointer and 2 invalids (generate exceptions) + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(0, -1, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 0, Array); + + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, -1, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 1, Array); + + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 2, Array); + + set_array(Array, NULL, (PVOID)2, (PVOID)3); + ret = g_alloc(HeapHandle, 0, 1, 1, Array); + INT_EXPECTED(ret, 1); + TEST_FREE(1, ERROR_INVALID_PARAMETER, 0, HeapHandle, HEAP_GENERATE_EXCEPTIONS, 3, Array); + + // Array is non-NULL and contents are 3 valid pointers + set_array(Array, NULL, NULL, NULL); + ret = g_alloc(HeapHandle, 0, 3, 3, Array); + INT_EXPECTED(ret, 3); + TEST_FREE(3, -1, 0, HeapHandle, 0, 3, Array); +} + +START_TEST(MultiHeap) +{ + g_ntdll = LoadLibrary(TEXT("ntdll.dll")); + ok(g_ntdll != NULL, "Cannot load ntdll.dll\n"); + + g_alloc = (RTLMULTIPLEALLOCATEHEAP)GetProcAddress(g_ntdll, "RtlMultipleAllocateHeap"); + ok(g_alloc != NULL, "Cannot get RtlMultipleAllocateHeap\n"); + + g_free = (RTLMULTIPLEFREEHEAP)GetProcAddress(g_ntdll, "RtlMultipleFreeHeap"); + ok(g_free != NULL, "Cannot get RtlMultipleFreeHeap\n"); + + if (g_ntdll && g_alloc && g_free) + { + MultiHeapAllocTest(); + MultiHeapFreeTest(); + } + + FreeLibrary(g_ntdll); +} Index: rostests/apitests/kernel32/testlist.c =================================================================== --- rostests/apitests/kernel32/testlist.c (revision 73408) +++ rostests/apitests/kernel32/testlist.c (working copy) @@ -13,6 +13,7 @@ extern void func_lstrcpynW(void); extern void func_Mailslot(void); extern void func_MultiByteToWideChar(void); +extern void func_MultiHeap(void); extern void func_PrivMoveFileIdentityW(void); extern void func_SetConsoleWindowInfo(void); extern void func_SetCurrentDirectory(void); @@ -33,6 +34,7 @@ { "lstrcpynW", func_lstrcpynW }, { "MailslotRead", func_Mailslot }, { "MultiByteToWideChar", func_MultiByteToWideChar }, + { "MultiHeap", func_MultiHeap }, { "PrivMoveFileIdentityW", func_PrivMoveFileIdentityW }, { "SetConsoleWindowInfo", func_SetConsoleWindowInfo }, { "SetCurrentDirectory", func_SetCurrentDirectory },