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);
355 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
357 /* Length > sizeof(OBJECT_ATTRIBUTES) */
359 status = pNtOpenKey(&key, am, &attr);
361 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
364 static void test_NtCreateKey(void)
367 OBJECT_ATTRIBUTES attr;
369 ACCESS_MASK am = GENERIC_ALL;
373 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
374 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
375 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
378 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
379 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
380 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
382 /* Only accessmask */
383 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
384 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
385 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
387 /* Key and accessmask */
388 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
389 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
390 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
392 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
394 /* Only attributes */
395 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
396 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
398 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
399 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
401 /* Length > sizeof(OBJECT_ATTRIBUTES) */
403 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
404 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
409 static void test_NtSetValueKey(void)
413 OBJECT_ATTRIBUTES attr;
414 ACCESS_MASK am = KEY_WRITE;
415 UNICODE_STRING ValName;
418 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
419 status = pNtOpenKey(&key, am, &attr);
420 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
422 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
423 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
424 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
425 pRtlFreeUnicodeString(&ValName);
427 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
428 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
429 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
430 pRtlFreeUnicodeString(&ValName);
435 static void test_RtlOpenCurrentUser(void)
439 status=pRtlOpenCurrentUser(KEY_READ, &handle);
440 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
444 static void test_RtlCheckRegistryKey(void)
448 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
449 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
451 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
452 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
455 static void test_NtFlushKey(void)
459 OBJECT_ATTRIBUTES attr;
460 ACCESS_MASK am = KEY_ALL_ACCESS;
462 status = pNtFlushKey(NULL);
463 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
465 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
466 pNtOpenKey(&hkey, am, &attr);
468 status = pNtFlushKey(hkey);
469 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
474 static void test_NtQueryValueKey(void)
478 OBJECT_ATTRIBUTES attr;
479 UNICODE_STRING ValName;
480 KEY_VALUE_BASIC_INFORMATION *basic_info;
481 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
482 KEY_VALUE_FULL_INFORMATION *full_info;
485 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
487 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
488 status = pNtOpenKey(&key, KEY_READ, &attr);
489 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
491 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
492 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
493 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
494 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
495 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
496 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
497 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
498 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
500 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
501 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
502 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
503 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
504 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
505 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
506 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
507 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
508 HeapFree(GetProcessHeap(), 0, basic_info);
510 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
511 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
512 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
513 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
514 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
515 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
516 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
517 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
519 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
520 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
521 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
522 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
523 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
524 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
525 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
526 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
527 HeapFree(GetProcessHeap(), 0, partial_info);
529 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
530 full_info = HeapAlloc(GetProcessHeap(), 0, len);
531 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
532 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
533 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
534 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
535 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
536 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
537 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
538 "NtQueryValueKey returned wrong len %d\n", len);
539 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
541 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
542 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
543 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
544 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
545 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
546 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
547 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
548 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
549 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
550 *(DWORD *)((char *)full_info + full_info->DataOffset));
551 HeapFree(GetProcessHeap(), 0, full_info);
553 pRtlFreeUnicodeString(&ValName);
554 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
556 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
557 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
558 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
559 memset(partial_info, 0xbd, len+1);
560 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
561 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
562 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
563 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
564 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
565 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
566 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
569 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
570 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
571 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
572 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
573 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
574 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
575 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
576 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
577 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
578 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
579 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
580 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
582 HeapFree(GetProcessHeap(), 0, partial_info);
584 pRtlFreeUnicodeString(&ValName);
588 static void test_NtDeleteKey(void)
592 OBJECT_ATTRIBUTES attr;
593 ACCESS_MASK am = KEY_ALL_ACCESS;
595 status = pNtDeleteKey(NULL);
596 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
598 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
599 status = pNtOpenKey(&hkey, am, &attr);
601 status = pNtDeleteKey(hkey);
602 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
605 static void test_RtlpNtQueryValueKey(void)
609 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
610 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
613 static void test_symlinks(void)
615 static const WCHAR linkW[] = {'l','i','n','k',0};
616 static const WCHAR valueW[] = {'v','a','l','u','e',0};
617 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
618 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
619 static UNICODE_STRING null_str;
621 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
623 UNICODE_STRING symlink_str, link_str, target_str, value_str;
624 HANDLE root, key, link;
625 OBJECT_ATTRIBUTES attr;
627 DWORD target_len, len, dw;
629 pRtlInitUnicodeString( &link_str, linkW );
630 pRtlInitUnicodeString( &symlink_str, symlinkW );
631 pRtlInitUnicodeString( &target_str, targetW + 1 );
632 pRtlInitUnicodeString( &value_str, valueW );
634 target_len = winetestpath.Length + sizeof(targetW);
635 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
636 memcpy( target, winetestpath.Buffer, winetestpath.Length );
637 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
639 attr.Length = sizeof(attr);
640 attr.RootDirectory = 0;
642 attr.ObjectName = &winetestpath;
643 attr.SecurityDescriptor = NULL;
644 attr.SecurityQualityOfService = NULL;
646 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
647 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
649 attr.RootDirectory = root;
650 attr.ObjectName = &link_str;
651 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
652 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
654 /* REG_SZ is not allowed */
655 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
656 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
657 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
658 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
659 /* other values are not allowed */
660 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
661 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
663 /* try opening the target through the link */
665 attr.ObjectName = &link_str;
666 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
667 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
669 attr.ObjectName = &target_str;
670 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
671 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
674 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
675 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
678 attr.ObjectName = &link_str;
679 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
680 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
682 len = sizeof(buffer);
683 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
684 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
685 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
687 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
688 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
690 /* REG_LINK can be created in non-link keys */
691 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
692 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
693 len = sizeof(buffer);
694 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
695 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
696 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
697 "wrong len %u\n", len );
698 status = pNtDeleteValueKey( key, &symlink_str );
699 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
704 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
705 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
707 len = sizeof(buffer);
708 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
709 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
710 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
712 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
713 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
716 /* now open the symlink itself */
718 attr.RootDirectory = root;
719 attr.Attributes = OBJ_OPENLINK;
720 attr.ObjectName = &link_str;
721 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
722 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
724 len = sizeof(buffer);
725 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
726 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
727 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
728 "wrong len %u\n", len );
731 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
732 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
733 len = sizeof(buffer);
734 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
735 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
736 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
737 "wrong len %u\n", len );
740 /* reopen the link from itself */
742 attr.RootDirectory = link;
743 attr.Attributes = OBJ_OPENLINK;
744 attr.ObjectName = &null_str;
745 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
746 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
747 len = sizeof(buffer);
748 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
749 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
750 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
751 "wrong len %u\n", len );
754 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
755 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
756 len = sizeof(buffer);
757 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
758 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
759 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
760 "wrong len %u\n", len );
763 if (0) /* crashes the Windows kernel in most versions */
766 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
767 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
768 len = sizeof(buffer);
769 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
770 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
773 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
774 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
775 len = sizeof(buffer);
776 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
777 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
781 /* target with terminating null doesn't work */
782 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
783 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
784 attr.RootDirectory = root;
786 attr.ObjectName = &link_str;
787 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
788 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
790 /* relative symlink, works only on win2k */
791 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
792 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
793 attr.ObjectName = &link_str;
794 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
795 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
796 "NtOpenKey wrong status 0x%08x\n", status );
798 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
799 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
801 status = pNtDeleteKey( link );
802 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
805 attr.ObjectName = &target_str;
806 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
807 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
808 status = pNtDeleteKey( key );
809 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
814 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
815 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
816 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
817 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
818 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
819 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
821 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
822 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
823 "NtOpenKey failed: 0x%08x\n", status );
825 attr.Attributes = OBJ_OPENLINK;
826 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
827 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
830 status = pNtDeleteKey( link );
831 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
834 status = pNtDeleteKey( root );
835 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
838 pRtlFreeHeap(GetProcessHeap(), 0, target);
843 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
844 if(!InitFunctionPtrs())
846 pRtlFormatCurrentUserKeyPath(&winetestpath);
847 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
848 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
849 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
851 pRtlAppendUnicodeToString(&winetestpath, winetest);
855 test_NtSetValueKey();
856 test_RtlCheckRegistryKey();
857 test_RtlOpenCurrentUser();
858 test_RtlQueryRegistryValues();
859 test_RtlpNtQueryValueKey();
861 test_NtQueryValueKey();
865 pRtlFreeUnicodeString(&winetestpath);