--- /dev/null
+/* Unit test suite for Rtl* Registry API functions
+ *
+ * Copyright 2003 Thomas Mertes
+ * Copyright 2005 Brad DeMorrow
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through
+ * helper function RTL_GetKeyHandle().--Brad DeMorrow
+ *
+ */
+
+#include "ntdll_test.h"
+#include "winternl.h"
+#include "wine/library.h"
+#include "stdio.h"
+#include "winnt.h"
+#include "winnls.h"
+#include "stdlib.h"
+#include "wine/unicode.h"
+
+/* RtlQueryRegistryValues structs and defines */
+#define RTL_REGISTRY_ABSOLUTE 0
+#define RTL_REGISTRY_SERVICES 1
+#define RTL_REGISTRY_CONTROL 2
+#define RTL_REGISTRY_WINDOWS_NT 3
+#define RTL_REGISTRY_DEVICEMAP 4
+#define RTL_REGISTRY_USER 5
+
+#define RTL_REGISTRY_HANDLE 0x40000000
+#define RTL_REGISTRY_OPTIONAL 0x80000000
+
+#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001
+#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002
+#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004
+#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008
+#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010
+#define RTL_QUERY_REGISTRY_DIRECT 0x00000020
+#define RTL_QUERY_REGISTRY_DELETE 0x00000040
+
+typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR ValueName,
+ ULONG ValueType,
+ PVOID ValueData,
+ ULONG ValueLength,
+ PVOID Context,
+ PVOID EntryContext);
+
+typedef struct _RTL_QUERY_REGISTRY_TABLE {
+ PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
+ ULONG Flags;
+ PWSTR Name;
+ PVOID EntryContext;
+ ULONG DefaultType;
+ PVOID DefaultData;
+ ULONG DefaultLength;
+} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
+
+static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
+static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
+static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
+static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
+static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
+static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY);
+static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
+static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
+static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
+static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY);
+static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
+ ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
+ PULONG dispos );
+static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG,
+ ULONG, const PVOID, ULONG );
+static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
+static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
+static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
+static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
+static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
+static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
+static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
+static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
+
+static HMODULE hntdll = 0;
+static int CurrentTest = 0;
+static UNICODE_STRING winetestpath;
+
+static void InitFunctionPtrs(void)
+{
+ hntdll = LoadLibraryA("ntdll.dll");
+ ok(hntdll != 0, "LoadLibrary failed\n");
+ if (hntdll)
+ {
+ pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz");
+ pRtlCreateUnicodeString = (void*)GetProcAddress(hntdll, "RtlCreateUnicodeString");
+ pRtlFreeUnicodeString = (void*)GetProcAddress(hntdll, "RtlFreeUnicodeString");
+ pNtDeleteValueKey = (void*)GetProcAddress(hntdll, "NtDeleteValueKey");
+ pRtlQueryRegistryValues = (void*)GetProcAddress(hntdll, "RtlQueryRegistryValues");
+ pRtlCheckRegistryKey = (void*)GetProcAddress(hntdll, "RtlCheckRegistryKey");
+ pRtlOpenCurrentUser = (void*)GetProcAddress(hntdll, "RtlOpenCurrentUser");
+ pNtClose = (void*)GetProcAddress(hntdll, "NtClose");
+ pNtDeleteValueKey = (void*)GetProcAddress(hntdll, "NtDeleteValueKey");
+ pNtCreateKey = (void*)GetProcAddress(hntdll, "NtCreateKey");
+ pNtDeleteKey = (void*)GetProcAddress(hntdll, "NtDeleteKey");
+ pNtSetValueKey = (void*)GetProcAddress(hntdll, "NtSetValueKey");
+ pNtOpenKey = (void*)GetProcAddress(hntdll, "NtOpenKey");
+ pRtlFormatCurrentUserKeyPath = (void*)GetProcAddress(hntdll, "RtlFormatCurrentUserKeyPath");
+ pRtlReAllocateHeap = (void*)GetProcAddress(hntdll, "RtlReAllocateHeap");
+ pRtlAppendUnicodeToString = (void*)GetProcAddress(hntdll, "RtlAppendUnicodeToString");
+ pRtlUnicodeStringToAnsiString = (void*)GetProcAddress(hntdll, "RtlUnicodeStringToAnsiString");
+ pRtlFreeHeap = (void*)GetProcAddress(hntdll, "RtlFreeHeap");
+ pRtlAllocateHeap = (void*)GetProcAddress(hntdll, "RtlAllocateHeap");
+ pRtlZeroMemory = (void*)GetProcAddress(hntdll, "RtlZeroMemory");
+ }
+
+
+}
+
+static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
+ IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
+{
+ NTSTATUS ret = STATUS_SUCCESS;
+ int ValueNameLength = 0;
+ LPSTR ValName = 0;
+ trace("**Test %d**\n", CurrentTest);
+
+ if(ValueName)
+ {
+ ValueNameLength = strlenW(ValueName);
+
+ ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
+
+ WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
+
+ trace("ValueName: %s\n", ValName);
+ }
+ else
+ trace("ValueName: (null)\n");
+
+ switch(ValueType)
+ {
+ case REG_NONE:
+ trace("ValueType: REG_NONE\n");
+ trace("ValueData: %d\n", (int)ValueData);
+ break;
+
+ case REG_BINARY:
+ trace("ValueType: REG_BINARY\n");
+ trace("ValueData: %d\n", (int)ValueData);
+ break;
+
+ case REG_SZ:
+ trace("ValueType: REG_SZ\n");
+ trace("ValueData: %s\n", (char*)ValueData);
+ break;
+
+ case REG_MULTI_SZ:
+ trace("ValueType: REG_MULTI_SZ\n");
+ trace("ValueData: %s\n", (char*)ValueData);
+ break;
+
+ case REG_EXPAND_SZ:
+ trace("ValueType: REG_EXPAND_SZ\n");
+ trace("ValueData: %s\n", (char*)ValueData);
+ break;
+
+ case REG_DWORD:
+ trace("ValueType: REG_DWORD\n");
+ trace("ValueData: %d\n", (int)ValueData);
+ break;
+ };
+ trace("ValueLength: %d\n", (int)ValueLength);
+
+ if(CurrentTest == 0)
+ ok(1, "\n"); /*checks that QueryRoutine is called*/
+ if(CurrentTest > 7)
+ ok(!1, "Invalid Test Specified!\n");
+
+ CurrentTest++;
+
+ if(ValName)
+ pRtlFreeHeap(GetProcessHeap(), 0, ValName);
+
+ return ret;
+}
+
+static void test_RtlQueryRegistryValues(void)
+{
+
+ /*
+ ******************************
+ * QueryTable Flags *
+ ******************************
+ *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
+ *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
+ *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
+ *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
+ *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
+ *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
+ *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
+ ******************************
+
+
+ **Test layout(numbered according to CurrentTest value)**
+ 0)NOVALUE Just make sure call-back works
+ 1)Null Name See if QueryRoutine is called for every value in current key
+ 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
+ 3)REQUIRED Test for value that's not there
+ 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
+ 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
+ 6)DefaultType Test return values when key isn't present
+ 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
+ 8)DefaultLength Test Default Length with DefaultType = REG_SZ
+ 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
+ 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
+ 11)DefaultData Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be)
+ 12)Delete Try to delete value key
+
+ */
+ NTSTATUS status;
+ ULONG RelativeTo;
+
+ PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
+ RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
+
+ QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
+
+ pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
+
+ QueryTable[0].QueryRoutine = QueryRoutine;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
+ QueryTable[0].Name = NULL;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_BINARY;
+ QueryTable[0].DefaultData = NULL;
+ QueryTable[0].DefaultLength = 100;
+
+ QueryTable[1].QueryRoutine = QueryRoutine;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+ QueryTable[1].EntryContext = 0;
+ QueryTable[1].DefaultType = REG_NONE;
+ QueryTable[1].DefaultData = NULL;
+ QueryTable[1].DefaultLength = 0;
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+ QueryTable[2].EntryContext = 0;
+ QueryTable[2].DefaultType = REG_NONE;
+ QueryTable[2].DefaultData = NULL;
+ QueryTable[2].DefaultLength = 0;
+
+ status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
+ ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08lx\n", status);
+
+ pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
+}
+
+static void test_NtCreateKey(void)
+{
+ /*Create WineTest*/
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING ValName;
+ HKEY key;
+ ACCESS_MASK am = GENERIC_ALL;
+ NTSTATUS status;
+
+ InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
+ status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
+ ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\n", status);
+
+ pRtlFreeUnicodeString(&ValName);
+ pNtClose(&key);
+}
+
+static void test_NtSetValueKey(void)
+{
+ HANDLE key;
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES attr;
+ ACCESS_MASK am = KEY_WRITE;
+ UNICODE_STRING ValName;
+ DWORD data = 711;
+
+ pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
+
+ InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
+ status = pNtOpenKey(&key, am, &attr);
+ ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
+
+ status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
+ ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status);
+
+ pRtlFreeUnicodeString(&ValName);
+ pNtClose(&key);
+}
+
+static void test_RtlOpenCurrentUser(void)
+{
+ NTSTATUS status;
+ HKEY handle;
+ status=pRtlOpenCurrentUser(KEY_READ, &handle);
+ ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08lx\n", status);
+ pNtClose(&handle);
+}
+
+static void test_RtlCheckRegistryKey(void)
+{
+ NTSTATUS status;
+
+ status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
+ ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\n", status);
+
+ status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE & RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
+ ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE & RTL_REGISTRY_OPTIONAL: 0x%08lx\n", status);
+}
+
+static void test_NtDeleteKey()
+{
+ NTSTATUS status;
+ HANDLE hkey;
+ OBJECT_ATTRIBUTES attr;
+ ACCESS_MASK am = KEY_ALL_ACCESS;
+
+ InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
+ status = pNtOpenKey(&hkey, am, &attr);
+
+ status = pNtDeleteKey(hkey);
+ ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
+}
+
+START_TEST(reg)
+{
+ static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0};
+ InitFunctionPtrs();
+ pRtlFormatCurrentUserKeyPath(&winetestpath);
+ winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
+ winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
+ winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
+
+ pRtlAppendUnicodeToString(&winetestpath, winetest);
+
+ test_NtCreateKey();
+ test_NtSetValueKey();
+ test_RtlCheckRegistryKey();
+ test_RtlOpenCurrentUser();
+ test_RtlQueryRegistryValues();
+ test_NtDeleteKey();
+
+ pRtlFreeUnicodeString(&winetestpath);
+
+ FreeLibrary(hntdll);
+}