ntdll: Fix status returned for too-long registry value names.
[wine/multimedia.git] / dlls / ntdll / tests / reg.c
blobd56d4f8001f237be1d03c0b30ac77872f3bded92
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 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,
132 PULONG dispos );
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 NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
139 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
140 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
141 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
142 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
143 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
144 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
145 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
146 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(ACCESS_MASK,HANDLE*);
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(NtDeleteValueKey)
172 NTDLL_GET_PROC(RtlQueryRegistryValues)
173 NTDLL_GET_PROC(RtlCheckRegistryKey)
174 NTDLL_GET_PROC(RtlOpenCurrentUser)
175 NTDLL_GET_PROC(NtClose)
176 NTDLL_GET_PROC(NtDeleteValueKey)
177 NTDLL_GET_PROC(NtCreateKey)
178 NTDLL_GET_PROC(NtFlushKey)
179 NTDLL_GET_PROC(NtDeleteKey)
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(RtlReAllocateHeap)
186 NTDLL_GET_PROC(RtlAppendUnicodeToString)
187 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
188 NTDLL_GET_PROC(RtlFreeHeap)
189 NTDLL_GET_PROC(RtlAllocateHeap)
190 NTDLL_GET_PROC(RtlZeroMemory)
191 NTDLL_GET_PROC(RtlpNtQueryValueKey)
192 NTDLL_GET_PROC(RtlOpenCurrentUser)
193 return TRUE;
195 #undef NTDLL_GET_PROC
197 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
198 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
200 NTSTATUS ret = STATUS_SUCCESS;
201 int ValueNameLength = 0;
202 LPSTR ValName = 0;
203 trace("**Test %d**\n", CurrentTest);
205 if(ValueName)
207 ValueNameLength = lstrlenW(ValueName);
209 ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
211 WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
213 trace("ValueName: %s\n", ValName);
215 else
216 trace("ValueName: (null)\n");
218 switch(ValueType)
220 case REG_NONE:
221 trace("ValueType: REG_NONE\n");
222 trace("ValueData: %p\n", ValueData);
223 break;
225 case REG_BINARY:
226 trace("ValueType: REG_BINARY\n");
227 trace("ValueData: %p\n", ValueData);
228 break;
230 case REG_SZ:
231 trace("ValueType: REG_SZ\n");
232 trace("ValueData: %s\n", (char*)ValueData);
233 break;
235 case REG_MULTI_SZ:
236 trace("ValueType: REG_MULTI_SZ\n");
237 trace("ValueData: %s\n", (char*)ValueData);
238 break;
240 case REG_EXPAND_SZ:
241 trace("ValueType: REG_EXPAND_SZ\n");
242 trace("ValueData: %s\n", (char*)ValueData);
243 break;
245 case REG_DWORD:
246 trace("ValueType: REG_DWORD\n");
247 trace("ValueData: %p\n", ValueData);
248 break;
250 trace("ValueLength: %d\n", (int)ValueLength);
252 if(CurrentTest == 0)
253 ok(1, "\n"); /*checks that QueryRoutine is called*/
254 if(CurrentTest > 7)
255 ok(!1, "Invalid Test Specified!\n");
257 CurrentTest++;
259 if(ValName)
260 pRtlFreeHeap(GetProcessHeap(), 0, ValName);
262 return ret;
265 static void test_RtlQueryRegistryValues(void)
269 ******************************
270 * QueryTable Flags *
271 ******************************
272 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
273 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
274 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
275 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
276 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
277 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
278 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
279 ******************************
282 **Test layout(numbered according to CurrentTest value)**
283 0)NOVALUE Just make sure call-back works
284 1)Null Name See if QueryRoutine is called for every value in current key
285 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
286 3)REQUIRED Test for value that's not there
287 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
288 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
289 6)DefaultType Test return values when key isn't present
290 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
291 8)DefaultLength Test Default Length with DefaultType = REG_SZ
292 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
293 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
294 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
295 12)Delete Try to delete value key
298 NTSTATUS status;
299 ULONG RelativeTo;
301 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
302 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
304 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
306 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
308 QueryTable[0].QueryRoutine = QueryRoutine;
309 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
310 QueryTable[0].Name = NULL;
311 QueryTable[0].EntryContext = NULL;
312 QueryTable[0].DefaultType = REG_BINARY;
313 QueryTable[0].DefaultData = NULL;
314 QueryTable[0].DefaultLength = 100;
316 QueryTable[1].QueryRoutine = QueryRoutine;
317 QueryTable[1].Flags = 0;
318 QueryTable[1].Name = NULL;
319 QueryTable[1].EntryContext = 0;
320 QueryTable[1].DefaultType = REG_NONE;
321 QueryTable[1].DefaultData = NULL;
322 QueryTable[1].DefaultLength = 0;
324 QueryTable[2].QueryRoutine = NULL;
325 QueryTable[2].Flags = 0;
326 QueryTable[2].Name = NULL;
327 QueryTable[2].EntryContext = 0;
328 QueryTable[2].DefaultType = REG_NONE;
329 QueryTable[2].DefaultData = NULL;
330 QueryTable[2].DefaultLength = 0;
332 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
333 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
335 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
338 static void test_NtOpenKey(void)
340 HANDLE key;
341 NTSTATUS status;
342 OBJECT_ATTRIBUTES attr;
343 ACCESS_MASK am = KEY_READ;
345 /* All NULL */
346 status = pNtOpenKey(NULL, 0, NULL);
347 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
349 /* NULL attributes */
350 status = pNtOpenKey(&key, 0, NULL);
351 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
352 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
354 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
356 /* NULL key */
357 status = pNtOpenKey(NULL, am, &attr);
358 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
360 /* Length > sizeof(OBJECT_ATTRIBUTES) */
361 attr.Length *= 2;
362 status = pNtOpenKey(&key, am, &attr);
363 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
366 static void test_NtCreateKey(void)
368 /*Create WineTest*/
369 OBJECT_ATTRIBUTES attr;
370 HANDLE key, subkey;
371 ACCESS_MASK am = GENERIC_ALL;
372 NTSTATUS status;
373 UNICODE_STRING str;
375 /* All NULL */
376 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
377 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
378 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
380 /* Only the key */
381 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
382 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
383 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
385 /* Only accessmask */
386 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
387 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
388 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
390 /* Key and accessmask */
391 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
392 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
393 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
395 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
397 /* Only attributes */
398 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
399 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
400 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
402 /* Length > sizeof(OBJECT_ATTRIBUTES) */
403 attr.Length *= 2;
404 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
405 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
407 attr.Length = sizeof(attr);
408 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
409 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
411 attr.RootDirectory = key;
412 attr.ObjectName = &str;
414 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
415 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
416 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
417 pRtlFreeUnicodeString( &str );
419 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
420 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
421 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
422 pRtlFreeUnicodeString( &str );
424 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
425 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
426 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
427 pRtlFreeUnicodeString( &str );
429 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
430 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
431 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
432 "NtCreateKey failed: 0x%08x\n", status );
433 if (status == STATUS_SUCCESS)
435 pNtDeleteKey( subkey );
436 pNtClose( subkey );
438 pRtlFreeUnicodeString( &str );
440 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
441 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
442 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
443 pRtlFreeUnicodeString( &str );
444 pNtDeleteKey( subkey );
445 pNtClose( subkey );
447 pNtClose(key);
450 static void test_NtSetValueKey(void)
452 HANDLE key;
453 NTSTATUS status;
454 OBJECT_ATTRIBUTES attr;
455 ACCESS_MASK am = KEY_WRITE;
456 UNICODE_STRING ValName;
457 DWORD data = 711;
459 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
460 status = pNtOpenKey(&key, am, &attr);
461 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
463 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
464 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
465 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
466 pRtlFreeUnicodeString(&ValName);
468 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
469 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
470 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
471 pRtlFreeUnicodeString(&ValName);
473 pNtClose(key);
476 static void test_RtlOpenCurrentUser(void)
478 NTSTATUS status;
479 HANDLE handle;
480 status=pRtlOpenCurrentUser(KEY_READ, &handle);
481 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
482 pNtClose(handle);
485 static void test_RtlCheckRegistryKey(void)
487 NTSTATUS status;
489 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
490 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
492 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
493 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
496 static void test_NtFlushKey(void)
498 NTSTATUS status;
499 HANDLE hkey;
500 OBJECT_ATTRIBUTES attr;
501 ACCESS_MASK am = KEY_ALL_ACCESS;
503 status = pNtFlushKey(NULL);
504 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
506 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
507 pNtOpenKey(&hkey, am, &attr);
509 status = pNtFlushKey(hkey);
510 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
512 pNtClose(hkey);
515 static void test_NtQueryValueKey(void)
517 HANDLE key;
518 NTSTATUS status;
519 OBJECT_ATTRIBUTES attr;
520 UNICODE_STRING ValName;
521 KEY_VALUE_BASIC_INFORMATION *basic_info;
522 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
523 KEY_VALUE_FULL_INFORMATION *full_info;
524 DWORD len, expected;
526 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
528 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
529 status = pNtOpenKey(&key, KEY_READ, &attr);
530 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
532 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
533 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
534 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
535 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
536 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
537 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
538 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
539 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
541 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
542 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
543 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
544 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
545 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
546 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
547 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
548 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
549 HeapFree(GetProcessHeap(), 0, basic_info);
551 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
552 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
553 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
554 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
555 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
556 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
557 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
558 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
560 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
561 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
562 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
563 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
564 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
565 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
566 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
567 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
568 HeapFree(GetProcessHeap(), 0, partial_info);
570 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
571 full_info = HeapAlloc(GetProcessHeap(), 0, len);
572 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
573 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
574 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
575 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
576 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
577 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
578 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
579 "NtQueryValueKey returned wrong len %d\n", len);
580 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
582 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
583 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
584 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
585 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
586 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
587 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
588 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
589 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
590 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
591 *(DWORD *)((char *)full_info + full_info->DataOffset));
592 HeapFree(GetProcessHeap(), 0, full_info);
594 pRtlFreeUnicodeString(&ValName);
595 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
597 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
598 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
599 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
600 memset(partial_info, 0xbd, len+1);
601 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
602 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
603 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
604 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
605 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
606 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
607 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
609 expected = len;
610 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
611 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
612 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
613 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
614 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
615 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
616 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
617 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
618 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
619 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
620 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
621 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
623 HeapFree(GetProcessHeap(), 0, partial_info);
625 pRtlFreeUnicodeString(&ValName);
626 pNtClose(key);
629 static void test_NtDeleteKey(void)
631 NTSTATUS status;
632 HANDLE hkey;
633 OBJECT_ATTRIBUTES attr;
634 ACCESS_MASK am = KEY_ALL_ACCESS;
636 status = pNtDeleteKey(NULL);
637 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
639 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
640 status = pNtOpenKey(&hkey, am, &attr);
641 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
643 status = pNtDeleteKey(hkey);
644 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
647 static void test_RtlpNtQueryValueKey(void)
649 NTSTATUS status;
651 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
652 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
655 static void test_symlinks(void)
657 static const WCHAR linkW[] = {'l','i','n','k',0};
658 static const WCHAR valueW[] = {'v','a','l','u','e',0};
659 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
660 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
661 static UNICODE_STRING null_str;
662 char buffer[1024];
663 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
664 WCHAR *target;
665 UNICODE_STRING symlink_str, link_str, target_str, value_str;
666 HANDLE root, key, link;
667 OBJECT_ATTRIBUTES attr;
668 NTSTATUS status;
669 DWORD target_len, len, dw;
671 pRtlInitUnicodeString( &link_str, linkW );
672 pRtlInitUnicodeString( &symlink_str, symlinkW );
673 pRtlInitUnicodeString( &target_str, targetW + 1 );
674 pRtlInitUnicodeString( &value_str, valueW );
676 target_len = winetestpath.Length + sizeof(targetW);
677 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
678 memcpy( target, winetestpath.Buffer, winetestpath.Length );
679 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
681 attr.Length = sizeof(attr);
682 attr.RootDirectory = 0;
683 attr.Attributes = 0;
684 attr.ObjectName = &winetestpath;
685 attr.SecurityDescriptor = NULL;
686 attr.SecurityQualityOfService = NULL;
688 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
689 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
691 attr.RootDirectory = root;
692 attr.ObjectName = &link_str;
693 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
694 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
696 /* REG_SZ is not allowed */
697 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
698 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
699 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
700 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
701 /* other values are not allowed */
702 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
703 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
705 /* try opening the target through the link */
707 attr.ObjectName = &link_str;
708 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
709 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
711 attr.ObjectName = &target_str;
712 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
713 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
715 dw = 0xbeef;
716 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
717 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
718 pNtClose( key );
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, &value_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) + sizeof(DWORD), "wrong len %u\n", len );
729 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
730 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
732 /* REG_LINK can be created in non-link keys */
733 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
734 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
735 len = sizeof(buffer);
736 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
737 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
738 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
739 "wrong len %u\n", len );
740 status = pNtDeleteValueKey( key, &symlink_str );
741 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
743 pNtClose( key );
745 attr.Attributes = 0;
746 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
747 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
749 len = sizeof(buffer);
750 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
751 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
752 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
754 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
755 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
756 pNtClose( key );
758 /* now open the symlink itself */
760 attr.RootDirectory = root;
761 attr.Attributes = OBJ_OPENLINK;
762 attr.ObjectName = &link_str;
763 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
764 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
766 len = sizeof(buffer);
767 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
768 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
769 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
770 "wrong len %u\n", len );
771 pNtClose( key );
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_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
778 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
779 "wrong len %u\n", len );
780 pNtClose( key );
782 if (0) /* crashes the Windows kernel on some Vista systems */
784 /* reopen the link from itself */
786 attr.RootDirectory = link;
787 attr.Attributes = OBJ_OPENLINK;
788 attr.ObjectName = &null_str;
789 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
790 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
791 len = sizeof(buffer);
792 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
793 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
794 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
795 "wrong len %u\n", len );
796 pNtClose( key );
798 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
799 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
800 len = sizeof(buffer);
801 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
802 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
803 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
804 "wrong len %u\n", len );
805 pNtClose( key );
808 if (0) /* crashes the Windows kernel in most versions */
810 attr.RootDirectory = link;
811 attr.Attributes = 0;
812 attr.ObjectName = &null_str;
813 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
814 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
815 len = sizeof(buffer);
816 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
817 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
818 pNtClose( key );
820 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
821 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
822 len = sizeof(buffer);
823 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
824 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
825 pNtClose( key );
828 /* target with terminating null doesn't work */
829 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
830 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
831 attr.RootDirectory = root;
832 attr.Attributes = 0;
833 attr.ObjectName = &link_str;
834 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
835 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
837 /* relative symlink, works only on win2k */
838 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
839 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
840 attr.ObjectName = &link_str;
841 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
842 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
843 "NtOpenKey wrong status 0x%08x\n", status );
845 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
846 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
848 status = pNtDeleteKey( link );
849 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
850 pNtClose( link );
852 attr.ObjectName = &target_str;
853 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
854 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
855 status = pNtDeleteKey( key );
856 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
857 pNtClose( key );
859 /* symlink loop */
861 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
862 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
863 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
864 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
865 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
866 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
868 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
869 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
870 "NtOpenKey failed: 0x%08x\n", status );
872 attr.Attributes = OBJ_OPENLINK;
873 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
874 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
875 pNtClose( key );
877 status = pNtDeleteKey( link );
878 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
879 pNtClose( link );
881 status = pNtDeleteKey( root );
882 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
883 pNtClose( root );
885 pRtlFreeHeap(GetProcessHeap(), 0, target);
888 static WCHAR valueW[] = {'v','a','l','u','e'};
889 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
890 static const DWORD ptr_size = 8 * sizeof(void*);
892 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
894 char tmp[32];
895 NTSTATUS status;
896 OBJECT_ATTRIBUTES attr;
897 UNICODE_STRING str;
898 HANDLE key;
899 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
900 DWORD dw, len = sizeof(tmp);
902 attr.Length = sizeof(attr);
903 attr.RootDirectory = root;
904 attr.Attributes = OBJ_CASE_INSENSITIVE;
905 attr.ObjectName = &str;
906 attr.SecurityDescriptor = NULL;
907 attr.SecurityQualityOfService = NULL;
908 pRtlCreateUnicodeStringFromAsciiz( &str, name );
910 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
911 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
912 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
914 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
915 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
916 dw = 0;
917 else
919 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
920 dw = *(DWORD *)info->Data;
922 pNtClose( key );
923 pRtlFreeUnicodeString( &str );
924 return dw;
927 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
929 DWORD dw = get_key_value( root, name, flags );
930 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
932 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
934 static void test_redirection(void)
936 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
937 'M','a','c','h','i','n','e','\\',
938 'S','o','f','t','w','a','r','e',0};
939 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
940 'M','a','c','h','i','n','e','\\',
941 'S','o','f','t','w','a','r','e','\\',
942 'W','o','w','6','4','3','2','N','o','d','e',0};
943 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
944 'M','a','c','h','i','n','e','\\',
945 'S','o','f','t','w','a','r','e','\\',
946 'W','i','n','e',0};
947 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
948 'M','a','c','h','i','n','e','\\',
949 'S','o','f','t','w','a','r','e','\\',
950 'W','o','w','6','4','3','2','N','o','d','e','\\',
951 'W','i','n','e',0};
952 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
953 'M','a','c','h','i','n','e','\\',
954 'S','o','f','t','w','a','r','e','\\',
955 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
956 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
957 'M','a','c','h','i','n','e','\\',
958 'S','o','f','t','w','a','r','e','\\',
959 'W','o','w','6','4','3','2','N','o','d','e','\\',
960 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
961 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
962 'M','a','c','h','i','n','e','\\',
963 'S','o','f','t','w','a','r','e','\\',
964 'C','l','a','s','s','e','s','\\',
965 'W','i','n','e',0};
966 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
967 'M','a','c','h','i','n','e','\\',
968 'S','o','f','t','w','a','r','e','\\',
969 'C','l','a','s','s','e','s','\\',
970 'W','o','w','6','4','3','2','N','o','d','e','\\',
971 'W','i','n','e',0};
972 NTSTATUS status;
973 OBJECT_ATTRIBUTES attr;
974 UNICODE_STRING str;
975 char buffer[1024];
976 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
977 DWORD dw, len;
978 HANDLE key, root32, root64, key32, key64;
979 BOOL is_vista = FALSE;
981 if (ptr_size != 64)
983 ULONG is_wow64, len;
984 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
985 &is_wow64, sizeof(is_wow64), &len ) ||
986 !is_wow64)
988 trace( "Not on Wow64, no redirection\n" );
989 return;
993 attr.Length = sizeof(attr);
994 attr.RootDirectory = 0;
995 attr.Attributes = OBJ_CASE_INSENSITIVE;
996 attr.ObjectName = &str;
997 attr.SecurityDescriptor = NULL;
998 attr.SecurityQualityOfService = NULL;
1000 pRtlInitUnicodeString( &str, wine64W );
1001 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1002 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1004 pRtlInitUnicodeString( &str, wine32W );
1005 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1006 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1008 pRtlInitUnicodeString( &str, key64W );
1009 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1010 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1012 pRtlInitUnicodeString( &str, key32W );
1013 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1014 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1016 dw = 64;
1017 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1018 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1020 dw = 32;
1021 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1022 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1024 len = sizeof(buffer);
1025 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1026 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1027 dw = *(DWORD *)info->Data;
1028 ok( dw == 32, "wrong value %u\n", dw );
1030 len = sizeof(buffer);
1031 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1032 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1033 dw = *(DWORD *)info->Data;
1034 ok( dw == 64, "wrong value %u\n", dw );
1036 pRtlInitUnicodeString( &str, softwareW );
1037 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1038 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1040 if (ptr_size == 32)
1042 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1043 /* the new (and simpler) Win7 mechanism doesn't */
1044 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1046 trace( "using Vista-style Wow6432Node handling\n" );
1047 is_vista = TRUE;
1049 check_key_value( key, "Wine\\Winetest", 0, 32 );
1050 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1051 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1052 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1053 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1054 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1056 else
1058 check_key_value( key, "Wine\\Winetest", 0, 64 );
1059 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1061 pNtClose( key );
1063 if (ptr_size == 32)
1065 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1066 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1067 dw = get_key_value( key, "Wine\\Winetest", 0 );
1068 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1069 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1070 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1071 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1072 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1073 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1074 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1075 pNtClose( key );
1077 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1078 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1079 check_key_value( key, "Wine\\Winetest", 0, 32 );
1080 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1081 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1082 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1083 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1084 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1085 pNtClose( key );
1088 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1089 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1090 if (ptr_size == 64)
1092 /* KEY_WOW64 flags have no effect on 64-bit */
1093 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1094 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1095 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1096 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1098 else
1100 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1101 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1102 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1103 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1106 pRtlInitUnicodeString( &str, wownodeW );
1107 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1108 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1109 check_key_value( key, "Wine\\Winetest", 0, 32 );
1110 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1111 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1112 pNtClose( key );
1114 if (ptr_size == 32)
1116 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1117 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1118 dw = get_key_value( key, "Wine\\Winetest", 0 );
1119 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1120 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1121 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1122 pNtClose( key );
1124 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1125 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1126 check_key_value( key, "Wine\\Winetest", 0, 32 );
1127 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1128 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1129 pNtClose( key );
1132 pRtlInitUnicodeString( &str, wine32W );
1133 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1134 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1135 check_key_value( key, "Winetest", 0, 32 );
1136 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1137 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1138 pNtClose( key );
1140 if (ptr_size == 32)
1142 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1143 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1144 dw = get_key_value( key, "Winetest", 0 );
1145 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1146 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1147 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1148 pNtClose( key );
1150 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1151 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1152 check_key_value( key, "Winetest", 0, 32 );
1153 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1154 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1155 pNtClose( key );
1158 pRtlInitUnicodeString( &str, wine64W );
1159 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1160 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1161 check_key_value( key, "Winetest", 0, ptr_size );
1162 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1163 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1164 pNtClose( key );
1166 if (ptr_size == 32)
1168 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1169 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1170 dw = get_key_value( key, "Winetest", 0 );
1171 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1172 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1173 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1174 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1175 pNtClose( key );
1177 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1178 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1179 check_key_value( key, "Winetest", 0, 32 );
1180 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1181 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1182 pNtClose( key );
1185 status = pNtDeleteKey( key32 );
1186 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1187 pNtClose( key32 );
1189 status = pNtDeleteKey( key64 );
1190 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1191 pNtClose( key64 );
1193 pNtDeleteKey( root32 );
1194 pNtClose( root32 );
1195 pNtDeleteKey( root64 );
1196 pNtClose( root64 );
1198 /* Software\Classes is shared/reflected so behavior is different */
1200 pRtlInitUnicodeString( &str, classes64W );
1201 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1202 if (status == STATUS_ACCESS_DENIED)
1204 skip("Not authorized to modify the Classes key\n");
1205 return;
1207 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1209 pRtlInitUnicodeString( &str, classes32W );
1210 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1211 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1213 dw = 64;
1214 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1215 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1216 pNtClose( key64 );
1218 dw = 32;
1219 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1220 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1221 pNtClose( key32 );
1223 pRtlInitUnicodeString( &str, classes64W );
1224 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1225 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1226 len = sizeof(buffer);
1227 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1228 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1229 dw = *(DWORD *)info->Data;
1230 ok( dw == ptr_size, "wrong value %u\n", dw );
1232 pRtlInitUnicodeString( &str, classes32W );
1233 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1234 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1235 len = sizeof(buffer);
1236 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1237 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1238 dw = *(DWORD *)info->Data;
1239 ok( dw == 32, "wrong value %u\n", dw );
1241 pNtDeleteKey( key32 );
1242 pNtClose( key32 );
1243 pNtDeleteKey( key64 );
1244 pNtClose( key64 );
1247 static void test_long_value_name(void)
1249 HANDLE key;
1250 NTSTATUS status, expected;
1251 OBJECT_ATTRIBUTES attr;
1252 UNICODE_STRING ValName;
1253 DWORD i;
1255 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1256 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1257 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1259 ValName.MaximumLength = 0xfffc;
1260 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1261 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1262 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1263 ValName.Buffer[i] = 'a';
1264 ValName.Buffer[i] = 0;
1266 status = pNtDeleteValueKey(key, &ValName);
1267 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1268 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1269 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1270 "NtSetValueKey with long value name returned 0x%08x\n", status);
1271 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1272 status = pNtDeleteValueKey(key, &ValName);
1273 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1275 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1276 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1278 pRtlFreeUnicodeString(&ValName);
1279 pNtClose(key);
1282 START_TEST(reg)
1284 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1285 if(!InitFunctionPtrs())
1286 return;
1287 pRtlFormatCurrentUserKeyPath(&winetestpath);
1288 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1289 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1290 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1292 pRtlAppendUnicodeToString(&winetestpath, winetest);
1294 test_NtCreateKey();
1295 test_NtOpenKey();
1296 test_NtSetValueKey();
1297 test_RtlCheckRegistryKey();
1298 test_RtlOpenCurrentUser();
1299 test_RtlQueryRegistryValues();
1300 test_RtlpNtQueryValueKey();
1301 test_NtFlushKey();
1302 test_NtQueryValueKey();
1303 test_long_value_name();
1304 test_NtDeleteKey();
1305 test_symlinks();
1306 test_redirection();
1308 pRtlFreeUnicodeString(&winetestpath);
1310 FreeLibrary(hntdll);