ntdll/tests: Add KeyNameInformation tests.
[wine.git] / dlls / ntdll / tests / reg.c
blob22048f98e21c69db21377af8475573e1dce3f154
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"
26 #include "winternl.h"
27 #include "stdio.h"
28 #include "winnt.h"
29 #include "winnls.h"
30 #include "stdlib.h"
32 /* A test string */
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,
59 ULONG ValueType,
60 PVOID ValueData,
61 ULONG ValueLength,
62 PVOID Context,
63 PVOID EntryContext);
65 typedef struct _RTL_QUERY_REGISTRY_TABLE {
66 PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
67 ULONG Flags;
68 PWSTR Name;
69 PVOID EntryContext;
70 ULONG DefaultType;
71 PVOID DefaultData;
72 ULONG DefaultLength;
73 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
75 typedef struct _KEY_VALUE_BASIC_INFORMATION {
76 ULONG TitleIndex;
77 ULONG Type;
78 ULONG NameLength;
79 WCHAR Name[1];
80 } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
82 typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
83 ULONG TitleIndex;
84 ULONG Type;
85 ULONG DataLength;
86 UCHAR Data[1];
87 } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
89 typedef struct _KEY_VALUE_FULL_INFORMATION {
90 ULONG TitleIndex;
91 ULONG Type;
92 ULONG DataOffset;
93 ULONG DataLength;
94 ULONG NameLength;
95 WCHAR Name[1];
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) \
107 do { \
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; \
114 } while (0)
116 #endif
118 static BOOLEAN (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 * pNtFlushKey)(HANDLE);
128 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
129 static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
130 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
131 PULONG dispos );
132 static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,KEY_INFORMATION_CLASS,PVOID,ULONG,PULONG);
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 * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
137 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
138 static LONG (WINAPI * pRtlCompareUnicodeString)(const PUNICODE_STRING,const PUNICODE_STRING,BOOLEAN);
139 static BOOLEAN (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR);
140 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
141 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
142 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
143 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
144 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
145 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
146 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
148 static HMODULE hntdll = 0;
149 static int CurrentTest = 0;
150 static UNICODE_STRING winetestpath;
152 #define NTDLL_GET_PROC(func) \
153 p ## func = (void*)GetProcAddress(hntdll, #func); \
154 if(!p ## func) { \
155 trace("GetProcAddress(%s) failed\n", #func); \
156 FreeLibrary(hntdll); \
157 return FALSE; \
160 static BOOL InitFunctionPtrs(void)
162 hntdll = LoadLibraryA("ntdll.dll");
163 if(!hntdll) {
164 trace("Could not load ntdll.dll\n");
165 return FALSE;
167 NTDLL_GET_PROC(RtlInitUnicodeString)
168 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
169 NTDLL_GET_PROC(RtlCreateUnicodeString)
170 NTDLL_GET_PROC(RtlFreeUnicodeString)
171 NTDLL_GET_PROC(RtlQueryRegistryValues)
172 NTDLL_GET_PROC(RtlCheckRegistryKey)
173 NTDLL_GET_PROC(RtlOpenCurrentUser)
174 NTDLL_GET_PROC(NtClose)
175 NTDLL_GET_PROC(NtDeleteValueKey)
176 NTDLL_GET_PROC(NtCreateKey)
177 NTDLL_GET_PROC(NtFlushKey)
178 NTDLL_GET_PROC(NtDeleteKey)
179 NTDLL_GET_PROC(NtQueryKey)
180 NTDLL_GET_PROC(NtQueryValueKey)
181 NTDLL_GET_PROC(NtQueryInformationProcess)
182 NTDLL_GET_PROC(NtSetValueKey)
183 NTDLL_GET_PROC(NtOpenKey)
184 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
185 NTDLL_GET_PROC(RtlCompareUnicodeString)
186 NTDLL_GET_PROC(RtlReAllocateHeap)
187 NTDLL_GET_PROC(RtlAppendUnicodeToString)
188 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
189 NTDLL_GET_PROC(RtlFreeHeap)
190 NTDLL_GET_PROC(RtlAllocateHeap)
191 NTDLL_GET_PROC(RtlZeroMemory)
192 NTDLL_GET_PROC(RtlpNtQueryValueKey)
193 NTDLL_GET_PROC(RtlOpenCurrentUser)
194 return TRUE;
196 #undef NTDLL_GET_PROC
198 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
199 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
201 NTSTATUS ret = STATUS_SUCCESS;
202 int ValueNameLength = 0;
203 LPSTR ValName = 0;
204 trace("**Test %d**\n", CurrentTest);
206 if(ValueName)
208 ValueNameLength = lstrlenW(ValueName);
210 ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
212 WideCharToMultiByte(CP_ACP, 0, ValueName, ValueNameLength+1, ValName, ValueNameLength, NULL, NULL);
214 trace("ValueName: %s\n", ValName);
216 else
217 trace("ValueName: (null)\n");
219 switch(ValueType)
221 case REG_NONE:
222 trace("ValueType: REG_NONE\n");
223 trace("ValueData: %p\n", ValueData);
224 break;
226 case REG_BINARY:
227 trace("ValueType: REG_BINARY\n");
228 trace("ValueData: %p\n", ValueData);
229 break;
231 case REG_SZ:
232 trace("ValueType: REG_SZ\n");
233 trace("ValueData: %s\n", (char*)ValueData);
234 break;
236 case REG_MULTI_SZ:
237 trace("ValueType: REG_MULTI_SZ\n");
238 trace("ValueData: %s\n", (char*)ValueData);
239 break;
241 case REG_EXPAND_SZ:
242 trace("ValueType: REG_EXPAND_SZ\n");
243 trace("ValueData: %s\n", (char*)ValueData);
244 break;
246 case REG_DWORD:
247 trace("ValueType: REG_DWORD\n");
248 trace("ValueData: %p\n", ValueData);
249 break;
251 trace("ValueLength: %d\n", (int)ValueLength);
253 if(CurrentTest == 0)
254 ok(1, "\n"); /*checks that QueryRoutine is called*/
255 if(CurrentTest > 7)
256 ok(!1, "Invalid Test Specified!\n");
258 CurrentTest++;
260 if(ValName)
261 pRtlFreeHeap(GetProcessHeap(), 0, ValName);
263 return ret;
266 static void test_RtlQueryRegistryValues(void)
270 ******************************
271 * QueryTable Flags *
272 ******************************
273 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
274 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
275 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
276 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
277 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
278 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
279 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
280 ******************************
283 **Test layout(numbered according to CurrentTest value)**
284 0)NOVALUE Just make sure call-back works
285 1)Null Name See if QueryRoutine is called for every value in current key
286 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
287 3)REQUIRED Test for value that's not there
288 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
289 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
290 6)DefaultType Test return values when key isn't present
291 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
292 8)DefaultLength Test Default Length with DefaultType = REG_SZ
293 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
294 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
295 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
296 12)Delete Try to delete value key
299 NTSTATUS status;
300 ULONG RelativeTo;
302 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
303 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
305 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
307 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
309 QueryTable[0].QueryRoutine = QueryRoutine;
310 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
311 QueryTable[0].Name = NULL;
312 QueryTable[0].EntryContext = NULL;
313 QueryTable[0].DefaultType = REG_BINARY;
314 QueryTable[0].DefaultData = NULL;
315 QueryTable[0].DefaultLength = 100;
317 QueryTable[1].QueryRoutine = QueryRoutine;
318 QueryTable[1].Flags = 0;
319 QueryTable[1].Name = NULL;
320 QueryTable[1].EntryContext = 0;
321 QueryTable[1].DefaultType = REG_NONE;
322 QueryTable[1].DefaultData = NULL;
323 QueryTable[1].DefaultLength = 0;
325 QueryTable[2].QueryRoutine = NULL;
326 QueryTable[2].Flags = 0;
327 QueryTable[2].Name = NULL;
328 QueryTable[2].EntryContext = 0;
329 QueryTable[2].DefaultType = REG_NONE;
330 QueryTable[2].DefaultData = NULL;
331 QueryTable[2].DefaultLength = 0;
333 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
334 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
336 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
339 static void test_NtOpenKey(void)
341 HANDLE key;
342 NTSTATUS status;
343 OBJECT_ATTRIBUTES attr;
344 ACCESS_MASK am = KEY_READ;
346 /* All NULL */
347 status = pNtOpenKey(NULL, 0, NULL);
348 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
350 /* NULL attributes */
351 status = pNtOpenKey(&key, 0, NULL);
352 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
353 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
355 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
357 /* NULL key */
358 status = pNtOpenKey(NULL, am, &attr);
359 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
361 /* Length > sizeof(OBJECT_ATTRIBUTES) */
362 attr.Length *= 2;
363 status = pNtOpenKey(&key, am, &attr);
364 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
367 static void test_NtCreateKey(void)
369 /*Create WineTest*/
370 OBJECT_ATTRIBUTES attr;
371 HANDLE key, subkey;
372 ACCESS_MASK am = GENERIC_ALL;
373 NTSTATUS status;
374 UNICODE_STRING str;
376 /* All NULL */
377 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
378 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
379 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
381 /* Only the key */
382 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
383 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
384 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
386 /* Only accessmask */
387 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
388 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
389 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
391 /* Key and accessmask */
392 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
393 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
394 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
396 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
398 /* Only attributes */
399 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
400 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
401 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
403 /* Length > sizeof(OBJECT_ATTRIBUTES) */
404 attr.Length *= 2;
405 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
406 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
408 attr.Length = sizeof(attr);
409 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
410 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
412 attr.RootDirectory = key;
413 attr.ObjectName = &str;
415 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
416 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
417 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
418 pRtlFreeUnicodeString( &str );
420 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
421 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
422 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
423 pRtlFreeUnicodeString( &str );
425 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
426 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
427 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
428 pRtlFreeUnicodeString( &str );
430 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
431 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
432 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
433 "NtCreateKey failed: 0x%08x\n", status );
434 if (status == STATUS_SUCCESS)
436 pNtDeleteKey( subkey );
437 pNtClose( subkey );
439 pRtlFreeUnicodeString( &str );
441 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
442 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
443 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
444 pRtlFreeUnicodeString( &str );
445 pNtDeleteKey( subkey );
446 pNtClose( subkey );
448 pNtClose(key);
451 static void test_NtSetValueKey(void)
453 HANDLE key;
454 NTSTATUS status;
455 OBJECT_ATTRIBUTES attr;
456 ACCESS_MASK am = KEY_WRITE;
457 UNICODE_STRING ValName;
458 DWORD data = 711;
460 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
461 status = pNtOpenKey(&key, am, &attr);
462 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
464 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
465 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
466 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
467 pRtlFreeUnicodeString(&ValName);
469 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
470 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
471 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
472 pRtlFreeUnicodeString(&ValName);
474 pNtClose(key);
477 static void test_RtlOpenCurrentUser(void)
479 NTSTATUS status;
480 HANDLE handle;
481 status=pRtlOpenCurrentUser(KEY_READ, &handle);
482 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
483 pNtClose(handle);
486 static void test_RtlCheckRegistryKey(void)
488 NTSTATUS status;
490 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
491 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
493 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
494 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
497 static void test_NtFlushKey(void)
499 NTSTATUS status;
500 HANDLE hkey;
501 OBJECT_ATTRIBUTES attr;
502 ACCESS_MASK am = KEY_ALL_ACCESS;
504 status = pNtFlushKey(NULL);
505 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
507 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
508 pNtOpenKey(&hkey, am, &attr);
510 status = pNtFlushKey(hkey);
511 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
513 pNtClose(hkey);
516 static void test_NtQueryValueKey(void)
518 HANDLE key;
519 NTSTATUS status;
520 OBJECT_ATTRIBUTES attr;
521 UNICODE_STRING ValName;
522 KEY_VALUE_BASIC_INFORMATION *basic_info;
523 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
524 KEY_VALUE_FULL_INFORMATION *full_info;
525 DWORD len, expected;
527 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
529 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
530 status = pNtOpenKey(&key, KEY_READ, &attr);
531 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
533 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
534 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
535 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
536 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
537 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
538 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
539 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
540 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
542 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
543 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
544 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
545 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
546 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
547 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
548 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
549 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
550 HeapFree(GetProcessHeap(), 0, basic_info);
552 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
553 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
554 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
555 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
556 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
557 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
558 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
559 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
561 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
562 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
563 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
564 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
565 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
566 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
567 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
568 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
569 HeapFree(GetProcessHeap(), 0, partial_info);
571 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
572 full_info = HeapAlloc(GetProcessHeap(), 0, len);
573 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
574 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
575 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
576 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
577 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
578 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
579 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
580 "NtQueryValueKey returned wrong len %d\n", len);
581 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
583 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
584 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
585 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
586 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
587 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
588 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
589 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
590 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
591 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
592 *(DWORD *)((char *)full_info + full_info->DataOffset));
593 HeapFree(GetProcessHeap(), 0, full_info);
595 pRtlFreeUnicodeString(&ValName);
596 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
598 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
599 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
600 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
601 memset(partial_info, 0xbd, len+1);
602 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
603 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
604 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
605 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
606 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
607 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
608 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
610 expected = len;
611 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
612 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
613 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
614 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
615 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
616 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
617 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
618 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
619 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
620 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
621 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
622 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
624 HeapFree(GetProcessHeap(), 0, partial_info);
626 pRtlFreeUnicodeString(&ValName);
627 pNtClose(key);
630 static void test_NtDeleteKey(void)
632 NTSTATUS status;
633 HANDLE hkey;
634 OBJECT_ATTRIBUTES attr;
635 ACCESS_MASK am = KEY_ALL_ACCESS;
637 status = pNtDeleteKey(NULL);
638 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
640 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
641 status = pNtOpenKey(&hkey, am, &attr);
642 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
644 status = pNtDeleteKey(hkey);
645 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
648 static void test_RtlpNtQueryValueKey(void)
650 NTSTATUS status;
652 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
653 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
656 static void test_symlinks(void)
658 static const WCHAR linkW[] = {'l','i','n','k',0};
659 static const WCHAR valueW[] = {'v','a','l','u','e',0};
660 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
661 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
662 static UNICODE_STRING null_str;
663 char buffer[1024];
664 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
665 WCHAR *target;
666 UNICODE_STRING symlink_str, link_str, target_str, value_str;
667 HANDLE root, key, link;
668 OBJECT_ATTRIBUTES attr;
669 NTSTATUS status;
670 DWORD target_len, len, dw;
672 pRtlInitUnicodeString( &link_str, linkW );
673 pRtlInitUnicodeString( &symlink_str, symlinkW );
674 pRtlInitUnicodeString( &target_str, targetW + 1 );
675 pRtlInitUnicodeString( &value_str, valueW );
677 target_len = winetestpath.Length + sizeof(targetW);
678 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
679 memcpy( target, winetestpath.Buffer, winetestpath.Length );
680 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
682 attr.Length = sizeof(attr);
683 attr.RootDirectory = 0;
684 attr.Attributes = 0;
685 attr.ObjectName = &winetestpath;
686 attr.SecurityDescriptor = NULL;
687 attr.SecurityQualityOfService = NULL;
689 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
690 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
692 attr.RootDirectory = root;
693 attr.ObjectName = &link_str;
694 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
695 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
697 /* REG_SZ is not allowed */
698 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
699 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
700 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
701 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
702 /* other values are not allowed */
703 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
704 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
706 /* try opening the target through the link */
708 attr.ObjectName = &link_str;
709 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
710 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
712 attr.ObjectName = &target_str;
713 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
714 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
716 dw = 0xbeef;
717 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
718 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
719 pNtClose( key );
721 attr.ObjectName = &link_str;
722 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
723 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
725 len = sizeof(buffer);
726 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
727 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
728 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
730 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
731 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
733 /* REG_LINK can be created in non-link keys */
734 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
735 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
736 len = sizeof(buffer);
737 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
738 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
739 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
740 "wrong len %u\n", len );
741 status = pNtDeleteValueKey( key, &symlink_str );
742 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
744 pNtClose( key );
746 attr.Attributes = 0;
747 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
748 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
750 len = sizeof(buffer);
751 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
752 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
753 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
755 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
756 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
757 pNtClose( key );
759 /* now open the symlink itself */
761 attr.RootDirectory = root;
762 attr.Attributes = OBJ_OPENLINK;
763 attr.ObjectName = &link_str;
764 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
765 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
767 len = sizeof(buffer);
768 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
769 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
770 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
771 "wrong len %u\n", len );
772 pNtClose( key );
774 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
775 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
776 len = sizeof(buffer);
777 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
778 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
779 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
780 "wrong len %u\n", len );
781 pNtClose( key );
783 if (0) /* crashes the Windows kernel on some Vista systems */
785 /* reopen the link from itself */
787 attr.RootDirectory = link;
788 attr.Attributes = OBJ_OPENLINK;
789 attr.ObjectName = &null_str;
790 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
791 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
792 len = sizeof(buffer);
793 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
794 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
795 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
796 "wrong len %u\n", len );
797 pNtClose( key );
799 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
800 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
801 len = sizeof(buffer);
802 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
803 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
804 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
805 "wrong len %u\n", len );
806 pNtClose( key );
809 if (0) /* crashes the Windows kernel in most versions */
811 attr.RootDirectory = link;
812 attr.Attributes = 0;
813 attr.ObjectName = &null_str;
814 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
815 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
816 len = sizeof(buffer);
817 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
818 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
819 pNtClose( key );
821 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
822 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
823 len = sizeof(buffer);
824 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
825 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
826 pNtClose( key );
829 /* target with terminating null doesn't work */
830 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
831 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
832 attr.RootDirectory = root;
833 attr.Attributes = 0;
834 attr.ObjectName = &link_str;
835 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
836 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
838 /* relative symlink, works only on win2k */
839 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
840 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
841 attr.ObjectName = &link_str;
842 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
843 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
844 "NtOpenKey wrong status 0x%08x\n", status );
846 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
847 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
849 status = pNtDeleteKey( link );
850 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
851 pNtClose( link );
853 attr.ObjectName = &target_str;
854 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
855 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
856 status = pNtDeleteKey( key );
857 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
858 pNtClose( key );
860 /* symlink loop */
862 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
863 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
864 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
865 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
866 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
867 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
869 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
870 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
871 "NtOpenKey failed: 0x%08x\n", status );
873 attr.Attributes = OBJ_OPENLINK;
874 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
875 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
876 pNtClose( key );
878 status = pNtDeleteKey( link );
879 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
880 pNtClose( link );
882 status = pNtDeleteKey( root );
883 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
884 pNtClose( root );
886 pRtlFreeHeap(GetProcessHeap(), 0, target);
889 static WCHAR valueW[] = {'v','a','l','u','e'};
890 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
891 static const DWORD ptr_size = 8 * sizeof(void*);
893 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
895 char tmp[32];
896 NTSTATUS status;
897 OBJECT_ATTRIBUTES attr;
898 UNICODE_STRING str;
899 HANDLE key;
900 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
901 DWORD dw, len = sizeof(tmp);
903 attr.Length = sizeof(attr);
904 attr.RootDirectory = root;
905 attr.Attributes = OBJ_CASE_INSENSITIVE;
906 attr.ObjectName = &str;
907 attr.SecurityDescriptor = NULL;
908 attr.SecurityQualityOfService = NULL;
909 pRtlCreateUnicodeStringFromAsciiz( &str, name );
911 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
912 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
913 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
915 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
916 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
917 dw = 0;
918 else
920 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
921 dw = *(DWORD *)info->Data;
923 pNtClose( key );
924 pRtlFreeUnicodeString( &str );
925 return dw;
928 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
930 DWORD dw = get_key_value( root, name, flags );
931 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
933 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
935 static void test_redirection(void)
937 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
938 'M','a','c','h','i','n','e','\\',
939 'S','o','f','t','w','a','r','e',0};
940 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
941 'M','a','c','h','i','n','e','\\',
942 'S','o','f','t','w','a','r','e','\\',
943 'W','o','w','6','4','3','2','N','o','d','e',0};
944 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
945 'M','a','c','h','i','n','e','\\',
946 'S','o','f','t','w','a','r','e','\\',
947 'W','i','n','e',0};
948 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
949 'M','a','c','h','i','n','e','\\',
950 'S','o','f','t','w','a','r','e','\\',
951 'W','o','w','6','4','3','2','N','o','d','e','\\',
952 'W','i','n','e',0};
953 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
954 'M','a','c','h','i','n','e','\\',
955 'S','o','f','t','w','a','r','e','\\',
956 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
957 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
958 'M','a','c','h','i','n','e','\\',
959 'S','o','f','t','w','a','r','e','\\',
960 'W','o','w','6','4','3','2','N','o','d','e','\\',
961 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
962 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
963 'M','a','c','h','i','n','e','\\',
964 'S','o','f','t','w','a','r','e','\\',
965 'C','l','a','s','s','e','s','\\',
966 'W','i','n','e',0};
967 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
968 'M','a','c','h','i','n','e','\\',
969 'S','o','f','t','w','a','r','e','\\',
970 'C','l','a','s','s','e','s','\\',
971 'W','o','w','6','4','3','2','N','o','d','e','\\',
972 'W','i','n','e',0};
973 NTSTATUS status;
974 OBJECT_ATTRIBUTES attr;
975 UNICODE_STRING str;
976 char buffer[1024];
977 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
978 DWORD dw, len;
979 HANDLE key, root32, root64, key32, key64;
980 BOOL is_vista = FALSE;
982 if (ptr_size != 64)
984 ULONG is_wow64, len;
985 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
986 &is_wow64, sizeof(is_wow64), &len ) ||
987 !is_wow64)
989 trace( "Not on Wow64, no redirection\n" );
990 return;
994 attr.Length = sizeof(attr);
995 attr.RootDirectory = 0;
996 attr.Attributes = OBJ_CASE_INSENSITIVE;
997 attr.ObjectName = &str;
998 attr.SecurityDescriptor = NULL;
999 attr.SecurityQualityOfService = NULL;
1001 pRtlInitUnicodeString( &str, wine64W );
1002 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1003 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1005 pRtlInitUnicodeString( &str, wine32W );
1006 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1007 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1009 pRtlInitUnicodeString( &str, key64W );
1010 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1011 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1013 pRtlInitUnicodeString( &str, key32W );
1014 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1015 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1017 dw = 64;
1018 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1019 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1021 dw = 32;
1022 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1023 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1025 len = sizeof(buffer);
1026 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1027 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1028 dw = *(DWORD *)info->Data;
1029 ok( dw == 32, "wrong value %u\n", dw );
1031 len = sizeof(buffer);
1032 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1033 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1034 dw = *(DWORD *)info->Data;
1035 ok( dw == 64, "wrong value %u\n", dw );
1037 pRtlInitUnicodeString( &str, softwareW );
1038 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1039 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1041 if (ptr_size == 32)
1043 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1044 /* the new (and simpler) Win7 mechanism doesn't */
1045 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1047 trace( "using Vista-style Wow6432Node handling\n" );
1048 is_vista = TRUE;
1050 check_key_value( key, "Wine\\Winetest", 0, 32 );
1051 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1052 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1053 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1054 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1055 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1057 else
1059 check_key_value( key, "Wine\\Winetest", 0, 64 );
1060 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1062 pNtClose( key );
1064 if (ptr_size == 32)
1066 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1067 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1068 dw = get_key_value( key, "Wine\\Winetest", 0 );
1069 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1070 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1071 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1072 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1073 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1074 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1075 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1076 pNtClose( key );
1078 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1079 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1080 check_key_value( key, "Wine\\Winetest", 0, 32 );
1081 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1082 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1083 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1084 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1085 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1086 pNtClose( key );
1089 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1090 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1091 if (ptr_size == 64)
1093 /* KEY_WOW64 flags have no effect on 64-bit */
1094 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1095 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1096 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1097 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1099 else
1101 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1102 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1103 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1104 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1107 pRtlInitUnicodeString( &str, wownodeW );
1108 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1109 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1110 check_key_value( key, "Wine\\Winetest", 0, 32 );
1111 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1112 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1113 pNtClose( key );
1115 if (ptr_size == 32)
1117 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1118 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1119 dw = get_key_value( key, "Wine\\Winetest", 0 );
1120 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1121 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1122 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1123 pNtClose( key );
1125 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1126 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1127 check_key_value( key, "Wine\\Winetest", 0, 32 );
1128 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1129 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1130 pNtClose( key );
1133 pRtlInitUnicodeString( &str, wine32W );
1134 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1135 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1136 check_key_value( key, "Winetest", 0, 32 );
1137 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1138 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1139 pNtClose( key );
1141 if (ptr_size == 32)
1143 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1144 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1145 dw = get_key_value( key, "Winetest", 0 );
1146 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1147 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1148 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1149 pNtClose( key );
1151 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1152 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1153 check_key_value( key, "Winetest", 0, 32 );
1154 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1155 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1156 pNtClose( key );
1159 pRtlInitUnicodeString( &str, wine64W );
1160 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1161 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1162 check_key_value( key, "Winetest", 0, ptr_size );
1163 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1164 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1165 pNtClose( key );
1167 if (ptr_size == 32)
1169 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1170 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1171 dw = get_key_value( key, "Winetest", 0 );
1172 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1173 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1174 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1175 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1176 pNtClose( key );
1178 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1179 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1180 check_key_value( key, "Winetest", 0, 32 );
1181 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1182 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1183 pNtClose( key );
1186 status = pNtDeleteKey( key32 );
1187 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1188 pNtClose( key32 );
1190 status = pNtDeleteKey( key64 );
1191 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1192 pNtClose( key64 );
1194 pNtDeleteKey( root32 );
1195 pNtClose( root32 );
1196 pNtDeleteKey( root64 );
1197 pNtClose( root64 );
1199 /* Software\Classes is shared/reflected so behavior is different */
1201 pRtlInitUnicodeString( &str, classes64W );
1202 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1203 if (status == STATUS_ACCESS_DENIED)
1205 skip("Not authorized to modify the Classes key\n");
1206 return;
1208 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1210 pRtlInitUnicodeString( &str, classes32W );
1211 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1212 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1214 dw = 64;
1215 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1216 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1217 pNtClose( key64 );
1219 dw = 32;
1220 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1221 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1222 pNtClose( key32 );
1224 pRtlInitUnicodeString( &str, classes64W );
1225 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1226 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1227 len = sizeof(buffer);
1228 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1229 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1230 dw = *(DWORD *)info->Data;
1231 ok( dw == ptr_size, "wrong value %u\n", dw );
1233 pRtlInitUnicodeString( &str, classes32W );
1234 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1235 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1236 len = sizeof(buffer);
1237 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1238 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1239 dw = *(DWORD *)info->Data;
1240 ok( dw == 32, "wrong value %u\n", dw );
1242 pNtDeleteKey( key32 );
1243 pNtClose( key32 );
1244 pNtDeleteKey( key64 );
1245 pNtClose( key64 );
1248 static void test_long_value_name(void)
1250 HANDLE key;
1251 NTSTATUS status, expected;
1252 OBJECT_ATTRIBUTES attr;
1253 UNICODE_STRING ValName;
1254 DWORD i;
1256 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1257 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1258 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1260 ValName.MaximumLength = 0xfffc;
1261 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1262 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1263 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1264 ValName.Buffer[i] = 'a';
1265 ValName.Buffer[i] = 0;
1267 status = pNtDeleteValueKey(key, &ValName);
1268 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1269 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1270 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1271 "NtSetValueKey with long value name returned 0x%08x\n", status);
1272 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1273 status = pNtDeleteValueKey(key, &ValName);
1274 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1276 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1277 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1279 pRtlFreeUnicodeString(&ValName);
1280 pNtClose(key);
1283 static void test_NtQueryKey(void)
1285 HANDLE key;
1286 NTSTATUS status;
1287 OBJECT_ATTRIBUTES attr;
1288 ULONG len;
1289 KEY_NAME_INFORMATION *info = NULL;
1290 UNICODE_STRING str;
1292 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1293 status = pNtOpenKey(&key, KEY_READ, &attr);
1294 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1296 status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &len);
1297 if (status == STATUS_INVALID_PARAMETER) {
1298 win_skip("KeyNameInformation is not supported\n");
1299 pNtClose(key);
1300 return;
1302 todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1304 info = HeapAlloc(GetProcessHeap(), 0, len);
1305 status = pNtQueryKey(key, KeyNameInformation, info, len, &len);
1306 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1308 str.Buffer = info->Name;
1309 str.Length = info->NameLength;
1310 todo_wine ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1311 "got %s, expected %s\n",
1312 wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1313 wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1315 HeapFree(GetProcessHeap(), 0, info);
1316 pNtClose(key);
1319 START_TEST(reg)
1321 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1322 if(!InitFunctionPtrs())
1323 return;
1324 pRtlFormatCurrentUserKeyPath(&winetestpath);
1325 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1326 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1327 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1329 pRtlAppendUnicodeToString(&winetestpath, winetest);
1331 test_NtCreateKey();
1332 test_NtOpenKey();
1333 test_NtSetValueKey();
1334 test_RtlCheckRegistryKey();
1335 test_RtlOpenCurrentUser();
1336 test_RtlQueryRegistryValues();
1337 test_RtlpNtQueryValueKey();
1338 test_NtFlushKey();
1339 test_NtQueryKey();
1340 test_NtQueryValueKey();
1341 test_long_value_name();
1342 test_NtDeleteKey();
1343 test_symlinks();
1344 test_redirection();
1346 pRtlFreeUnicodeString(&winetestpath);
1348 FreeLibrary(hntdll);