For React Native. This marks the end of the series.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/rtl.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index 1828b860531..a1647241283 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -674,11 +674,30 @@ BOOLEAN WINAPI RtlDeleteElementGenericTable(RTL_GENERIC_TABLE *table, void *valu */ void * WINAPI RtlEnumerateGenericTableWithoutSplaying(RTL_GENERIC_TABLE *table, PVOID *previous) { - static int warn_once; + RTL_SPLAY_LINKS *child;
- if (!warn_once++) - FIXME("(%p, %p) stub!\n", table, previous); - return NULL; + TRACE("(%p, %p)\n", table, previous); + + if (RtlIsGenericTableEmpty(table)) + return NULL; + + if (!*previous) + { + /* Find the smallest element */ + child = table->TableRoot; + while (RtlLeftChild(child)) + child = RtlLeftChild(child); + } + else + { + /* Find the successor of the previous element */ + child = RtlRealSuccessor(*previous); + if (!child) + return NULL; + } + + *previous = child; + return get_data_from_splay_links(child); }
/******************************************************************************
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/tests/rtl.c | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index eaee2768c6a..a08b021add7 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -92,6 +92,7 @@ static HMODULE hntdll = 0; static PRTL_SPLAY_LINKS (WINAPI *pRtlDelete)(PRTL_SPLAY_LINKS); static void (WINAPI *pRtlDeleteNoSplay)(PRTL_SPLAY_LINKS, PRTL_SPLAY_LINKS *); static BOOLEAN (WINAPI *pRtlDeleteElementGenericTable)(PRTL_GENERIC_TABLE,PVOID); +static void * (WINAPI *pRtlEnumerateGenericTableWithoutSplaying)(PRTL_GENERIC_TABLE, PVOID *); static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T); static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE); static VOID (WINAPI *pRtlFillMemoryUlong)(LPVOID,SIZE_T,ULONG); @@ -161,6 +162,7 @@ static void InitFunctionPtrs(void) pRtlDelete = (void *)GetProcAddress(hntdll, "RtlDelete"); pRtlDeleteElementGenericTable = (void *)GetProcAddress(hntdll, "RtlDeleteElementGenericTable"); pRtlDeleteNoSplay = (void *)GetProcAddress(hntdll, "RtlDeleteNoSplay"); + pRtlEnumerateGenericTableWithoutSplaying = (void *)GetProcAddress(hntdll, "RtlEnumerateGenericTableWithoutSplaying"); pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory"); pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory"); pRtlFillMemoryUlong = (void *)GetProcAddress(hntdll, "RtlFillMemoryUlong"); @@ -5150,6 +5152,70 @@ static void test_RtlLookupElementGenericTable(void) } }
+static void test_RtlEnumerateGenericTableWithoutSplaying(void) +{ + static const int elements[] = {1, 9, 5, 4, 7, 2, 3, 8, 6}; + static const int expected_elements[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + RTL_SPLAY_LINKS *old_table_root; + BOOLEAN new_element, success; + RTL_GENERIC_TABLE table; + int i, value, *ret; + void *restart_key; + + if (!pRtlEnumerateGenericTableWithoutSplaying) + { + win_skip("RtlEnumerateGenericTableWithoutSplaying is unavailable.\n"); + return; + } + + pRtlInitializeGenericTable(&table, generic_compare_proc, generic_allocate_proc, generic_free_proc, NULL); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == value, "Got unexpected pointer.\n"); + ok(new_element, "Expected new element.\n"); + } + + /* Test that restart key is a pointer to RTL_SPLAY_LINKS pointing to returned element */ + restart_key = NULL; + ret = pRtlEnumerateGenericTableWithoutSplaying(&table, &restart_key); + ok(ret && *ret == expected_elements[0], "Expected %d at %d, got %d.\n", + expected_elements[0], 0, ret ? *ret : -1); + ok(restart_key == get_splay_links_from_data(ret), "Got unexpected restart key %p.\n", restart_key); + + /* Test enumeration */ + old_table_root = table.TableRoot; + restart_key = NULL; + for (i = 0, ret = pRtlEnumerateGenericTableWithoutSplaying(&table, &restart_key); ret != NULL; + ret = pRtlEnumerateGenericTableWithoutSplaying(&table, &restart_key), i++) + { + ok(ret && *ret == expected_elements[i], "Expected %d at %d, got %d.\n", + expected_elements[i], i, ret ? *ret : -1); + ok(table.TableRoot == old_table_root, "Got unexpected TableRoot.\n"); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + + /* Test restarting enumeration */ + restart_key = NULL; + for (i = 0, ret = pRtlEnumerateGenericTableWithoutSplaying(&table, &restart_key); ret != NULL; + ret = pRtlEnumerateGenericTableWithoutSplaying(&table, &restart_key), i++) + { + ok(ret && *ret == expected_elements[i], "Expected %d at %d, got %d.\n", + expected_elements[i], i, ret ? *ret : -1); + ok(table.TableRoot == old_table_root, "Got unexpected TableRoot.\n"); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable %d failed.\n", elements[i]); + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -5215,4 +5281,5 @@ START_TEST(rtl) test_RtlInsertElementGenericTable(); test_RtlDeleteElementGenericTable(); test_RtlLookupElementGenericTable(); + test_RtlEnumerateGenericTableWithoutSplaying(); }
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/ntdll.spec | 2 +- dlls/ntdll/rtl.c | 36 +++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +- include/ddk/ntddk.h | 1 + 4 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index cb6682d7e5c..c0d4c5eede7 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -659,7 +659,7 @@ @ stdcall -arch=win32 -ret64 RtlEnlargedUnsignedMultiply(long long) @ stdcall RtlEnterCriticalSection(ptr) @ stub RtlEnumProcessHeaps -@ stub RtlEnumerateGenericTable +@ stdcall RtlEnumerateGenericTable(ptr long) # @ stub RtlEnumerateGenericTableAvl # @ stub RtlEnumerateGenericTableLikeADirectory @ stdcall RtlEnumerateGenericTableWithoutSplaying(ptr ptr) diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index a1647241283..a0588db6957 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -700,6 +700,42 @@ void * WINAPI RtlEnumerateGenericTableWithoutSplaying(RTL_GENERIC_TABLE *table, return get_data_from_splay_links(child); }
+/****************************************************************************** + * RtlEnumerateGenericTable [NTDLL.@] + * + * RtlEnumerateGenericTable() uses TableRoot to keep track of enumeration status according to tests. + * This also means that other functions that change TableRoot should not be used during enumerations. + * Otherwise, RtlEnumerateGenericTable() won't be able to find the correct next element when restart + * is FALSE. This is also the case on Windows. + */ +void * WINAPI RtlEnumerateGenericTable(RTL_GENERIC_TABLE *table, BOOLEAN restart) +{ + RTL_SPLAY_LINKS *child; + + TRACE("(%p, %d)\n", table, restart); + + if (RtlIsGenericTableEmpty(table)) + return NULL; + + if (restart) + { + /* Find the smallest element */ + child = table->TableRoot; + while (RtlLeftChild(child)) + child = RtlLeftChild(child); + } + else + { + /* Find the successor of the root */ + child = RtlRealSuccessor(table->TableRoot); + if (!child) + return NULL; + } + + table->TableRoot = RtlSplay(child); + return get_data_from_splay_links(child); +} + /****************************************************************************** * RtlNumberGenericTableElements [NTDLL.@] */ diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 49a29d06644..fea13ace291 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1070,7 +1070,7 @@ @ stdcall -arch=win32 -ret64 RtlEnlargedIntegerMultiply(long long) @ stdcall -arch=win32 RtlEnlargedUnsignedDivide(int64 long ptr) @ stdcall -arch=win32 -ret64 RtlEnlargedUnsignedMultiply(long long) -@ stub RtlEnumerateGenericTable +@ stdcall RtlEnumerateGenericTable(ptr long) @ stub RtlEnumerateGenericTableAvl @ stub RtlEnumerateGenericTableLikeADirectory @ stdcall RtlEnumerateGenericTableWithoutSplaying(ptr ptr) diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h index 36c52097c16..887d1749662 100644 --- a/include/ddk/ntddk.h +++ b/include/ddk/ntddk.h @@ -303,6 +303,7 @@ void WINAPI RtlCopyString(STRING*,const STRING*); PRTL_SPLAY_LINKS WINAPI RtlDelete(PRTL_SPLAY_LINKS); BOOLEAN WINAPI RtlDeleteElementGenericTable(PRTL_GENERIC_TABLE,PVOID); void WINAPI RtlDeleteNoSplay(PRTL_SPLAY_LINKS,PRTL_SPLAY_LINKS *); +void * WINAPI RtlEnumerateGenericTable(PRTL_GENERIC_TABLE,BOOLEAN); void * WINAPI RtlEnumerateGenericTableWithoutSplaying(PRTL_GENERIC_TABLE,PVOID*); void * WINAPI RtlEnumerateGenericTableWithoutSplayingAvl(PRTL_AVL_TABLE,PVOID*); BOOLEAN WINAPI RtlEqualString(const STRING*,const STRING*,BOOLEAN);
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/tests/rtl.c | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index a08b021add7..325a4a13b11 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -92,6 +92,7 @@ static HMODULE hntdll = 0; static PRTL_SPLAY_LINKS (WINAPI *pRtlDelete)(PRTL_SPLAY_LINKS); static void (WINAPI *pRtlDeleteNoSplay)(PRTL_SPLAY_LINKS, PRTL_SPLAY_LINKS *); static BOOLEAN (WINAPI *pRtlDeleteElementGenericTable)(PRTL_GENERIC_TABLE,PVOID); +static void * (WINAPI *pRtlEnumerateGenericTable)(PRTL_GENERIC_TABLE, BOOLEAN); static void * (WINAPI *pRtlEnumerateGenericTableWithoutSplaying)(PRTL_GENERIC_TABLE, PVOID *); static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T); static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE); @@ -162,6 +163,7 @@ static void InitFunctionPtrs(void) pRtlDelete = (void *)GetProcAddress(hntdll, "RtlDelete"); pRtlDeleteElementGenericTable = (void *)GetProcAddress(hntdll, "RtlDeleteElementGenericTable"); pRtlDeleteNoSplay = (void *)GetProcAddress(hntdll, "RtlDeleteNoSplay"); + pRtlEnumerateGenericTable = (void *)GetProcAddress(hntdll, "RtlEnumerateGenericTable"); pRtlEnumerateGenericTableWithoutSplaying = (void *)GetProcAddress(hntdll, "RtlEnumerateGenericTableWithoutSplaying"); pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory"); pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory"); @@ -5216,6 +5218,87 @@ static void test_RtlEnumerateGenericTableWithoutSplaying(void) } }
+static void test_RtlEnumerateGenericTable(void) +{ + static const int elements[] = {1, 9, 5, 4, 7, 2, 3, 8, 6}; + static const int expected_elements[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + int i, j, value, *ret, *first_ret = NULL, *last_ret = NULL; + BOOLEAN success, new_element; + RTL_GENERIC_TABLE table; + LIST_ENTRY *entry; + + if (!pRtlEnumerateGenericTable) + { + win_skip("RtlEnumerateGenericTable is unavailable.\n"); + return; + } + + pRtlInitializeGenericTable(&table, generic_compare_proc, generic_allocate_proc, generic_free_proc, NULL); + + ret = pRtlEnumerateGenericTable(&table, TRUE); + ok(!ret, "Got unexpected pointer.\n"); + + ret = pRtlEnumerateGenericTable(&table, FALSE); + ok(!ret, "Got unexpected pointer.\n"); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == value, "Got unexpected pointer.\n"); + ok(new_element, "Expected new element.\n"); + + if (i == 0) + first_ret = ret; + if (i == ARRAY_SIZE(elements) - 1) + last_ret = ret; + } + + /* Test enumeration */ + for (i = 0, ret = pRtlEnumerateGenericTable(&table, TRUE); ret != NULL; + ret = pRtlEnumerateGenericTable(&table, FALSE), i++) + { + ok(ret && *ret == expected_elements[i], "Expected %d at %d, got %d.\n", + expected_elements[i], i, ret ? *ret : -1); + ok(table.TableRoot == get_splay_links_from_data(ret), "Got unexpected TableRoot.\n"); + + /* Test that RtlEnumerateGenericTable() doesn't touch WhichOrderedElement, OrderedPointer and + * InsertOrderList. Additional tests show that RtlEnumerateGenericTable() uses TableRoot + * to keep track of enumeration status. This also means that if other functions that change + * TableRoot get used during enumerations, RtlEnumerateGenericTable() won't be able to find + * the correct next element, which is also the case on Windows */ + ok(table.WhichOrderedElement == 0, "Got unexpected WhichOrderedElement.\n"); + ok(table.OrderedPointer == &table.InsertOrderList, "Got unexpected OrderedPointer.\n"); + ok(table.InsertOrderList.Flink == get_list_entry_from_data(first_ret), "Got unexpected Flink.\n"); + ok(table.InsertOrderList.Blink == get_list_entry_from_data(last_ret), "Got unexpected Blink.\n"); + for (j = 0, entry = table.InsertOrderList.Flink; entry->Flink != table.InsertOrderList.Flink; + j++, entry = entry->Flink) + { + ret = (int *)get_data_from_list_entry(entry); + ok(*ret == elements[j], "Got unexpected pointer, value %d.\n", *ret); + } + ok(table.TableContext == NULL, "Got unexpected TableContext.\n"); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + + /* Test restarting enumeration */ + for (i = 0, ret = pRtlEnumerateGenericTable(&table, TRUE); ret != NULL; + ret = pRtlEnumerateGenericTable(&table, FALSE), i++) + { + ok(ret && *ret == expected_elements[i], "Expected %d at %d, got %d.\n", expected_elements[i], + i, ret ? *ret : -1); + ok(table.TableRoot == get_splay_links_from_data(ret), "Got unexpected TableRoot.\n"); + } + ok(i == ARRAY_SIZE(elements), "Got unexpected index %d.\n", i); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable failed.\n"); + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -5282,4 +5365,5 @@ START_TEST(rtl) test_RtlDeleteElementGenericTable(); test_RtlLookupElementGenericTable(); test_RtlEnumerateGenericTableWithoutSplaying(); + test_RtlEnumerateGenericTable(); }
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/rtl.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c index a0588db6957..bf1bfb793e7 100644 --- a/dlls/ntdll/rtl.c +++ b/dlls/ntdll/rtl.c @@ -249,6 +249,12 @@ static void *get_data_from_splay_links(RTL_SPLAY_LINKS *links) return (unsigned char *)links + FIELD_OFFSET(struct rtl_generic_table_entry, data); }
+static void *get_data_from_list_entry(LIST_ENTRY *list_entry) +{ + return (unsigned char *)list_entry + FIELD_OFFSET(struct rtl_generic_table_entry, data) + - FIELD_OFFSET(struct rtl_generic_table_entry, list_entry); +} + static LIST_ENTRY *get_list_entry_from_splay_links(RTL_SPLAY_LINKS *links) { return (LIST_ENTRY *)((unsigned char *)links + FIELD_OFFSET(struct rtl_generic_table_entry, list_entry)); @@ -750,8 +756,130 @@ ULONG WINAPI RtlNumberGenericTableElements(RTL_GENERIC_TABLE *table) */ void * WINAPI RtlGetElementGenericTable(RTL_GENERIC_TABLE *table, ULONG index) { - FIXME("(%p, %lu) stub!\n", table, index); - return NULL; + ULONG count, ordered_element_index; + LIST_ENTRY *list_entry; + BOOL forward; + + TRACE("(%p, %lu)\n", table, index); + + if (index >= table->NumberGenericTableElements) + return NULL; + + /* No OrderedPointer, use list header InsertOrderList */ + if (table->WhichOrderedElement == 0) + { + /* + * | lower half | upper half | + * ^ ^ ^ ^ + * head, 0 | | tail, table->NumberGenericTableElements - 1 + * | (table->NumberGenericTableElements - 1) / 2 + * index closer to head + */ + if (index <= (table->NumberGenericTableElements - 1) / 2) + { + list_entry = table->InsertOrderList.Flink; + count = index; + forward = TRUE; + } + /* + * | lower half | upper half | + * ^ ^ ^ ^ + * head, 0 | | tail, table->NumberGenericTableElements - 1 + * | index closer to tail + * (table->NumberGenericTableElements - 1) / 2 + */ + else + { + list_entry = table->InsertOrderList.Blink; + count = table->NumberGenericTableElements - index - 1; + forward = FALSE; + } + } + /* Has OrderedPointer, decide to use list header or OrderedPointer */ + else + { + ordered_element_index = table->WhichOrderedElement - 1; + + /* + * | -------------- | ---------- | + * ^ ^ ^ ^ + * head, 0 | | table->NumberGenericTableElements - 1 + * | ordered_element_index + * index, 0 <= index <= ordered_element_index + */ + if (index <= ordered_element_index) + { + /* + * | ------------------- | + * ^ ^ ^ + * | <--d1--> | <--d2--> | + * head, 0 | ordered_element_index + * index + * + */ + /* d1 <= d2, index is closer to head, forward from head */ + if (index <= ordered_element_index - index) + { + list_entry = table->InsertOrderList.Flink; + count = index; + forward = TRUE; + } + /* d1 > d2, index is closer to ordered_element_index, backward from ordered_element_index */ + else + { + list_entry = table->OrderedPointer; + count = ordered_element_index - index; + forward = FALSE; + } + } + /* + * | ------ | ---------- | + * ^ ^ ^ ^ + * head, 0 | | tail, table->NumberGenericTableElements - 1 + * | index, ordered_element_index < index <= table->NumberGenericTableElements - 1 + * ordered_element_index + */ + else + { + /* + * | --------------------------------| + * ^ ^ ^ + * | <--------d1--------> | <--d2--> | + * ordered_element_index | tail, table->NumberGenericTableElements - 1 + * index + * + */ + /* d1 <= d2, index is closer to ordered_element_index, forward from ordered_element_index */ + if (index - ordered_element_index <= table->NumberGenericTableElements - index - 1) + { + list_entry = table->OrderedPointer; + count = index - ordered_element_index; + forward = TRUE; + } + /* d1 > d2, index is closer to tail, backward from tail */ + else + { + list_entry = table->InsertOrderList.Blink; + count = table->NumberGenericTableElements - index - 1; + forward = FALSE; + } + } + } + + if (forward) + { + while (count--) + list_entry = list_entry->Flink; + } + else + { + while (count--) + list_entry = list_entry->Blink; + } + + table->OrderedPointer = list_entry; + table->WhichOrderedElement = index + 1; + return get_data_from_list_entry(list_entry); }
/******************************************************************************
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/tests/rtl.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 325a4a13b11..ac53c8dcdcc 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -101,6 +101,7 @@ static VOID (WINAPI *pRtlZeroMemory)(LPVOID,SIZE_T); static USHORT (FASTCALL *pRtlUshortByteSwap)(USHORT source); static ULONG (FASTCALL *pRtlUlongByteSwap)(ULONG source); static ULONGLONG (FASTCALL *pRtlUlonglongByteSwap)(ULONGLONG source); +static void * (WINAPI *pRtlGetElementGenericTable)(PRTL_GENERIC_TABLE, ULONG); static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD); static PVOID (WINAPI *pRtlInsertElementGenericTable)(PRTL_GENERIC_TABLE, PVOID, CLONG, PBOOLEAN); @@ -172,6 +173,7 @@ static void InitFunctionPtrs(void) pRtlUshortByteSwap = (void *)GetProcAddress(hntdll, "RtlUshortByteSwap"); pRtlUlongByteSwap = (void *)GetProcAddress(hntdll, "RtlUlongByteSwap"); pRtlUlonglongByteSwap = (void *)GetProcAddress(hntdll, "RtlUlonglongByteSwap"); + pRtlGetElementGenericTable = (void *)GetProcAddress(hntdll, "RtlGetElementGenericTable"); pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode"); pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode"); pRtlInsertElementGenericTable = (void *)GetProcAddress(hntdll, "RtlInsertElementGenericTable"); @@ -5299,6 +5301,91 @@ static void test_RtlEnumerateGenericTable(void) } }
+static void test_RtlGetElementGenericTable(void) +{ + static const int elements[] = {9, 1, 5, 4, 15, 11, 2, 3, 8, 6, 0, 10, 13, 14, 7, 12}; + RTL_SPLAY_LINKS *old_table_root; + BOOLEAN success, new_element; + RTL_GENERIC_TABLE table; + int i, value, *ret; + + if (!pRtlGetElementGenericTable) + { + win_skip("RtlGetElementGenericTable is unavailable.\n"); + return; + } + + pRtlInitializeGenericTable(&table, generic_compare_proc, generic_allocate_proc, generic_free_proc, NULL); + + ret = pRtlGetElementGenericTable(&table, 0); + ok(!ret, "Got unexpected pointer.\n"); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == value, "Got unexpected pointer.\n"); + ok(new_element, "Expected new element.\n"); + } + + /* Test that RtlGetElementGenericTable() changes WhichOrderedElement and OrderedPointer, but not TableRoot */ + old_table_root = table.TableRoot; + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + ret = pRtlGetElementGenericTable(&table, i); + ok(ret && *ret == elements[i], "Got unexpected pointer.\n"); + ok(table.WhichOrderedElement == i + 1, "Got unexpected WhichOrderedElement %lu.\n", + table.WhichOrderedElement); + ok(table.OrderedPointer == get_list_entry_from_data(ret), "Got unexpected OrderedPointer.\n"); + ok(table.TableRoot == old_table_root, "Got unexpected TableRoot.\n"); + } + + /* RtlInsertElementGenericTable() shouldn't touch WhichOrderedElement */ + value = 20; + ret = pRtlInsertElementGenericTable(&table, &value, sizeof(value), &new_element); + ok(ret && *ret == 20, "Got unexpected pointer.\n"); + ok(new_element, "Expected new element.\n"); + ok(table.WhichOrderedElement == ARRAY_SIZE(elements), "Got unexpected WhichOrderedElement %lu.\n", + table.WhichOrderedElement); + + /* RtlGetElementGenericTable() updates WhichOrderedElement. WhichOrderedElement points to the + * result element but its index starts from 1 instead of 0 */ + ret = pRtlGetElementGenericTable(&table, 1); + ok(ret && *ret == elements[1], "Got unexpected pointer.\n"); + ok(table.WhichOrderedElement == 2, "Got unexpected WhichOrderedElement %lu.\n", + table.WhichOrderedElement); + ok(table.OrderedPointer == get_list_entry_from_data(ret), "Got unexpected OrderedPointer.\n"); + + /* RtlDeleteElementGenericTable() should reset WhichOrderedElement and OrderedPointer */ + value = 20; + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable failed.\n"); + ok(table.WhichOrderedElement == 0, "Got unexpected WhichOrderedElement %lu.\n", table.WhichOrderedElement); + ok(table.OrderedPointer == &table.InsertOrderList, "Got unexpected OrderedPointer.\n"); + + /* Out of order RtlGetElementGenericTable() calls */ + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + ret = pRtlGetElementGenericTable(&table, elements[i]); + ok(ret && *ret == elements[elements[i]], "Expected %d got %d at %d.\n", + elements[elements[i]], *ret, elements[i]); + ok(table.WhichOrderedElement == elements[i] + 1, "Got unexpected WhichOrderedElement %lu.\n", + table.WhichOrderedElement); + ok(table.OrderedPointer == get_list_entry_from_data(ret), "Got unexpected OrderedPointer.\n"); + } + + /* Out of range RtlGetElementGenericTable() call */ + ret = pRtlGetElementGenericTable(&table, ARRAY_SIZE(elements)); + ok(!ret, "Got unexpected pointer.\n"); + + for (i = 0; i < ARRAY_SIZE(elements); i++) + { + value = elements[i]; + success = pRtlDeleteElementGenericTable(&table, &value); + ok(success, "RtlDeleteElementGenericTable failed.\n"); + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -5366,4 +5453,5 @@ START_TEST(rtl) test_RtlLookupElementGenericTable(); test_RtlEnumerateGenericTableWithoutSplaying(); test_RtlEnumerateGenericTable(); + test_RtlGetElementGenericTable(); }