1 /* Unit test suite for Rtl* Registry API functions
3 * Copyright 2003 Thomas Mertes
4 * Copyright 2005 Brad DeMorrow
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
20 * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through
21 * helper function RTL_GetKeyHandle().--Brad DeMorrow
25 #include "ntdll_test.h"
33 static const WCHAR stringW[] = {'s', 't', 'r', 'i', 'n', 'g', 'W', 0};
34 /* A size, in bytes, short enough to cause truncation of the above */
35 #define STR_TRUNC_SIZE (sizeof(stringW)-2*sizeof(*stringW))
37 #ifndef __WINE_WINTERNL_H
39 /* RtlQueryRegistryValues structs and defines */
40 #define RTL_REGISTRY_ABSOLUTE 0
41 #define RTL_REGISTRY_SERVICES 1
42 #define RTL_REGISTRY_CONTROL 2
43 #define RTL_REGISTRY_WINDOWS_NT 3
44 #define RTL_REGISTRY_DEVICEMAP 4
45 #define RTL_REGISTRY_USER 5
47 #define RTL_REGISTRY_HANDLE 0x40000000
48 #define RTL_REGISTRY_OPTIONAL 0x80000000
50 #define RTL_QUERY_REGISTRY_SUBKEY 0x00000001
51 #define RTL_QUERY_REGISTRY_TOPKEY 0x00000002
52 #define RTL_QUERY_REGISTRY_REQUIRED 0x00000004
53 #define RTL_QUERY_REGISTRY_NOVALUE 0x00000008
54 #define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010
55 #define RTL_QUERY_REGISTRY_DIRECT 0x00000020
56 #define RTL_QUERY_REGISTRY_DELETE 0x00000040
58 typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR ValueName,
65 typedef struct _RTL_QUERY_REGISTRY_TABLE {
66 PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
73 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
75 typedef struct _KEY_VALUE_BASIC_INFORMATION {
80 } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
82 typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
87 } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
89 typedef struct _KEY_VALUE_FULL_INFORMATION {
96 } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
98 typedef enum _KEY_VALUE_INFORMATION_CLASS {
99 KeyValueBasicInformation,
100 KeyValueFullInformation,
101 KeyValuePartialInformation,
102 KeyValueFullInformationAlign64,
103 KeyValuePartialInformationAlign64
104 } KEY_VALUE_INFORMATION_CLASS;
106 #define InitializeObjectAttributes(p,n,a,r,s) \
108 (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
109 (p)->RootDirectory = r; \
110 (p)->Attributes = a; \
111 (p)->ObjectName = n; \
112 (p)->SecurityDescriptor = s; \
113 (p)->SecurityQualityOfService = NULL; \
118 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
119 static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
120 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
121 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
122 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
123 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
124 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE);
125 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
126 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
127 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
128 static NTSTATUS (WINAPI * pNtFlushKey)(HANDLE);
129 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
130 static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
131 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
133 static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
134 static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
135 ULONG, const void*, ULONG );
136 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
137 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
138 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
139 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
140 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
141 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
142 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
143 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
144 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
146 static HMODULE hntdll = 0;
147 static int CurrentTest = 0;
148 static UNICODE_STRING winetestpath;
150 #define NTDLL_GET_PROC(func) \
151 p ## func = (void*)GetProcAddress(hntdll, #func); \
153 trace("GetProcAddress(%s) failed\n", #func); \
154 FreeLibrary(hntdll); \
158 static BOOL InitFunctionPtrs(void)
160 hntdll = LoadLibraryA("ntdll.dll");
162 trace("Could not load ntdll.dll\n");
165 NTDLL_GET_PROC(RtlInitUnicodeString)
166 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
167 NTDLL_GET_PROC(RtlCreateUnicodeString)
168 NTDLL_GET_PROC(RtlFreeUnicodeString)
169 NTDLL_GET_PROC(NtDeleteValueKey)
170 NTDLL_GET_PROC(RtlQueryRegistryValues)
171 NTDLL_GET_PROC(RtlCheckRegistryKey)
172 NTDLL_GET_PROC(RtlOpenCurrentUser)
173 NTDLL_GET_PROC(NtClose)
174 NTDLL_GET_PROC(NtDeleteValueKey)
175 NTDLL_GET_PROC(NtCreateKey)
176 NTDLL_GET_PROC(NtFlushKey)
177 NTDLL_GET_PROC(NtDeleteKey)
178 NTDLL_GET_PROC(NtQueryValueKey)
179 NTDLL_GET_PROC(NtSetValueKey)
180 NTDLL_GET_PROC(NtOpenKey)
181 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
182 NTDLL_GET_PROC(RtlReAllocateHeap)
183 NTDLL_GET_PROC(RtlAppendUnicodeToString)
184 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
185 NTDLL_GET_PROC(RtlFreeHeap)
186 NTDLL_GET_PROC(RtlAllocateHeap)
187 NTDLL_GET_PROC(RtlZeroMemory)
188 NTDLL_GET_PROC(RtlpNtQueryValueKey)
191 #undef NTDLL_GET_PROC
193 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
194 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
196 NTSTATUS ret = STATUS_SUCCESS;
197 int ValueNameLength = 0;
199 trace("**Test %d**\n", CurrentTest);
203 ValueNameLength = lstrlenW(ValueName);
205 ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
207 WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
209 trace("ValueName: %s\n", ValName);
212 trace("ValueName: (null)\n");
217 trace("ValueType: REG_NONE\n");
218 trace("ValueData: %p\n", ValueData);
222 trace("ValueType: REG_BINARY\n");
223 trace("ValueData: %p\n", ValueData);
227 trace("ValueType: REG_SZ\n");
228 trace("ValueData: %s\n", (char*)ValueData);
232 trace("ValueType: REG_MULTI_SZ\n");
233 trace("ValueData: %s\n", (char*)ValueData);
237 trace("ValueType: REG_EXPAND_SZ\n");
238 trace("ValueData: %s\n", (char*)ValueData);
242 trace("ValueType: REG_DWORD\n");
243 trace("ValueData: %p\n", ValueData);
246 trace("ValueLength: %d\n", (int)ValueLength);
249 ok(1, "\n"); /*checks that QueryRoutine is called*/
251 ok(!1, "Invalid Test Specified!\n");
256 pRtlFreeHeap(GetProcessHeap(), 0, ValName);
261 static void test_RtlQueryRegistryValues(void)
265 ******************************
267 ******************************
268 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
269 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
270 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
271 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
272 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
273 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
274 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
275 ******************************
278 **Test layout(numbered according to CurrentTest value)**
279 0)NOVALUE Just make sure call-back works
280 1)Null Name See if QueryRoutine is called for every value in current key
281 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
282 3)REQUIRED Test for value that's not there
283 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
284 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
285 6)DefaultType Test return values when key isn't present
286 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
287 8)DefaultLength Test Default Length with DefaultType = REG_SZ
288 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
289 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
290 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
291 12)Delete Try to delete value key
297 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
298 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
300 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
302 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
304 QueryTable[0].QueryRoutine = QueryRoutine;
305 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
306 QueryTable[0].Name = NULL;
307 QueryTable[0].EntryContext = NULL;
308 QueryTable[0].DefaultType = REG_BINARY;
309 QueryTable[0].DefaultData = NULL;
310 QueryTable[0].DefaultLength = 100;
312 QueryTable[1].QueryRoutine = QueryRoutine;
313 QueryTable[1].Flags = 0;
314 QueryTable[1].Name = NULL;
315 QueryTable[1].EntryContext = 0;
316 QueryTable[1].DefaultType = REG_NONE;
317 QueryTable[1].DefaultData = NULL;
318 QueryTable[1].DefaultLength = 0;
320 QueryTable[2].QueryRoutine = NULL;
321 QueryTable[2].Flags = 0;
322 QueryTable[2].Name = NULL;
323 QueryTable[2].EntryContext = 0;
324 QueryTable[2].DefaultType = REG_NONE;
325 QueryTable[2].DefaultData = NULL;
326 QueryTable[2].DefaultLength = 0;
328 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
329 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
331 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
334 static void test_NtOpenKey(void)
338 OBJECT_ATTRIBUTES attr;
339 ACCESS_MASK am = KEY_READ;
342 status = pNtOpenKey(NULL, 0, NULL);
343 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
345 /* NULL attributes */
346 status = pNtOpenKey(&key, 0, NULL);
347 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
348 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
350 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
353 status = pNtOpenKey(NULL, am, &attr);
354 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
356 /* Length > sizeof(OBJECT_ATTRIBUTES) */
358 status = pNtOpenKey(&key, am, &attr);
359 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
362 static void test_NtCreateKey(void)
365 OBJECT_ATTRIBUTES attr;
367 ACCESS_MASK am = GENERIC_ALL;
371 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
372 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
373 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
376 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
377 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
378 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
380 /* Only accessmask */
381 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
382 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
383 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
385 /* Key and accessmask */
386 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
387 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
388 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
390 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
392 /* Only attributes */
393 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
394 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
396 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
397 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
399 /* Length > sizeof(OBJECT_ATTRIBUTES) */
401 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
402 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
407 static void test_NtSetValueKey(void)
411 OBJECT_ATTRIBUTES attr;
412 ACCESS_MASK am = KEY_WRITE;
413 UNICODE_STRING ValName;
416 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
417 status = pNtOpenKey(&key, am, &attr);
418 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
420 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
421 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
422 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
423 pRtlFreeUnicodeString(&ValName);
425 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
426 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
427 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
428 pRtlFreeUnicodeString(&ValName);
433 static void test_RtlOpenCurrentUser(void)
437 status=pRtlOpenCurrentUser(KEY_READ, &handle);
438 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
442 static void test_RtlCheckRegistryKey(void)
446 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
447 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
449 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
450 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
453 static void test_NtFlushKey(void)
457 OBJECT_ATTRIBUTES attr;
458 ACCESS_MASK am = KEY_ALL_ACCESS;
460 status = pNtFlushKey(NULL);
461 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
463 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
464 pNtOpenKey(&hkey, am, &attr);
466 status = pNtFlushKey(hkey);
467 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
472 static void test_NtQueryValueKey(void)
476 OBJECT_ATTRIBUTES attr;
477 UNICODE_STRING ValName;
478 KEY_VALUE_BASIC_INFORMATION *basic_info;
479 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
480 KEY_VALUE_FULL_INFORMATION *full_info;
483 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
485 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
486 status = pNtOpenKey(&key, KEY_READ, &attr);
487 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
489 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
490 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
491 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
492 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
493 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
494 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
495 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
496 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
498 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
499 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
500 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
501 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
502 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
503 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
504 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
505 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
506 HeapFree(GetProcessHeap(), 0, basic_info);
508 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
509 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
510 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
511 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
512 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
513 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
514 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
515 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
517 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
518 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
519 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
520 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
521 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
522 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
523 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
524 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
525 HeapFree(GetProcessHeap(), 0, partial_info);
527 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
528 full_info = HeapAlloc(GetProcessHeap(), 0, len);
529 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
530 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
531 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
532 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
533 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
534 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
535 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
536 "NtQueryValueKey returned wrong len %d\n", len);
537 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
539 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
540 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
541 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
542 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
543 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
544 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
545 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
546 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
547 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
548 *(DWORD *)((char *)full_info + full_info->DataOffset));
549 HeapFree(GetProcessHeap(), 0, full_info);
551 pRtlFreeUnicodeString(&ValName);
552 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
554 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
555 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
556 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
557 memset(partial_info, 0xbd, len+1);
558 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
559 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
560 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
561 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
562 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
563 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
564 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
567 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
568 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
569 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
570 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
571 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
572 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
573 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
574 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
575 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
576 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
577 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
578 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
580 HeapFree(GetProcessHeap(), 0, partial_info);
582 pRtlFreeUnicodeString(&ValName);
586 static void test_NtDeleteKey(void)
590 OBJECT_ATTRIBUTES attr;
591 ACCESS_MASK am = KEY_ALL_ACCESS;
593 status = pNtDeleteKey(NULL);
594 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
596 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
597 status = pNtOpenKey(&hkey, am, &attr);
599 status = pNtDeleteKey(hkey);
600 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
603 static void test_RtlpNtQueryValueKey(void)
607 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
608 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
611 static void test_symlinks(void)
613 static const WCHAR linkW[] = {'l','i','n','k',0};
614 static const WCHAR valueW[] = {'v','a','l','u','e',0};
615 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
616 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
617 static UNICODE_STRING null_str;
619 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
621 UNICODE_STRING symlink_str, link_str, target_str, value_str;
622 HANDLE root, key, link;
623 OBJECT_ATTRIBUTES attr;
625 DWORD target_len, len, dw;
627 pRtlInitUnicodeString( &link_str, linkW );
628 pRtlInitUnicodeString( &symlink_str, symlinkW );
629 pRtlInitUnicodeString( &target_str, targetW + 1 );
630 pRtlInitUnicodeString( &value_str, valueW );
632 target_len = winetestpath.Length + sizeof(targetW);
633 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
634 memcpy( target, winetestpath.Buffer, winetestpath.Length );
635 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
637 attr.Length = sizeof(attr);
638 attr.RootDirectory = 0;
640 attr.ObjectName = &winetestpath;
641 attr.SecurityDescriptor = NULL;
642 attr.SecurityQualityOfService = NULL;
644 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
645 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
647 attr.RootDirectory = root;
648 attr.ObjectName = &link_str;
649 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
650 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
652 /* REG_SZ is not allowed */
653 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
654 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
655 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
656 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
657 /* other values are not allowed */
658 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
659 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
661 /* try opening the target through the link */
663 attr.ObjectName = &link_str;
664 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
665 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
667 attr.ObjectName = &target_str;
668 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
669 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
672 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
673 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
676 attr.ObjectName = &link_str;
677 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
678 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
680 len = sizeof(buffer);
681 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
682 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
683 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
685 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
686 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
688 /* REG_LINK can be created in non-link keys */
689 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
690 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
691 len = sizeof(buffer);
692 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
693 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
694 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
695 "wrong len %u\n", len );
696 status = pNtDeleteValueKey( key, &symlink_str );
697 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
702 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
703 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
705 len = sizeof(buffer);
706 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
707 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
708 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
710 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
711 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
714 /* now open the symlink itself */
716 attr.RootDirectory = root;
717 attr.Attributes = OBJ_OPENLINK;
718 attr.ObjectName = &link_str;
719 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
720 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
722 len = sizeof(buffer);
723 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
724 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
725 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
726 "wrong len %u\n", len );
729 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
730 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
731 len = sizeof(buffer);
732 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
733 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
734 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
735 "wrong len %u\n", len );
738 /* reopen the link from itself */
740 attr.RootDirectory = link;
741 attr.Attributes = OBJ_OPENLINK;
742 attr.ObjectName = &null_str;
743 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
744 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
745 len = sizeof(buffer);
746 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
747 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
748 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
749 "wrong len %u\n", len );
752 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
753 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
754 len = sizeof(buffer);
755 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
756 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
757 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
758 "wrong len %u\n", len );
761 if (0) /* crashes the Windows kernel in most versions */
764 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
765 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
766 len = sizeof(buffer);
767 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
768 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
771 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
772 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
773 len = sizeof(buffer);
774 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
775 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
779 /* target with terminating null doesn't work */
780 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
781 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
782 attr.RootDirectory = root;
784 attr.ObjectName = &link_str;
785 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
786 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
788 /* relative symlink, works only on win2k */
789 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
790 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
791 attr.ObjectName = &link_str;
792 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
793 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
794 "NtOpenKey wrong status 0x%08x\n", status );
796 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
797 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
799 status = pNtDeleteKey( link );
800 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
803 attr.ObjectName = &target_str;
804 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
805 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
806 status = pNtDeleteKey( key );
807 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
812 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
813 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
814 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
815 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
816 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
817 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
819 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
820 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
821 "NtOpenKey failed: 0x%08x\n", status );
823 attr.Attributes = OBJ_OPENLINK;
824 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
825 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
828 status = pNtDeleteKey( link );
829 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
832 status = pNtDeleteKey( root );
833 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
836 pRtlFreeHeap(GetProcessHeap(), 0, target);
841 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
842 if(!InitFunctionPtrs())
844 pRtlFormatCurrentUserKeyPath(&winetestpath);
845 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
846 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
847 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
849 pRtlAppendUnicodeToString(&winetestpath, winetest);
853 test_NtSetValueKey();
854 test_RtlCheckRegistryKey();
855 test_RtlOpenCurrentUser();
856 test_RtlQueryRegistryValues();
857 test_RtlpNtQueryValueKey();
859 test_NtQueryValueKey();
863 pRtlFreeUnicodeString(&winetestpath);