widl: Print large enum constants in hex.
[wine] / dlls / ntdll / tests / reg.c
1 /* Unit test suite for Rtl* Registry API functions
2  *
3  * Copyright 2003 Thomas Mertes
4  * Copyright 2005 Brad DeMorrow
5  *
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.
10  *
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.
15  *
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
19  *
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
22  *
23  */
24
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"
31
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))
36
37 #ifndef __WINE_WINTERNL_H
38
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
46
47 #define RTL_REGISTRY_HANDLE       0x40000000
48 #define RTL_REGISTRY_OPTIONAL     0x80000000
49
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
57
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);
64
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;
74
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;
81
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;
88
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;
97
98 typedef enum _KEY_VALUE_INFORMATION_CLASS {
99     KeyValueBasicInformation,
100     KeyValueFullInformation,
101     KeyValuePartialInformation,
102     KeyValueFullInformationAlign64,
103     KeyValuePartialInformationAlign64
104 } KEY_VALUE_INFORMATION_CLASS;
105
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)
115
116 #endif
117
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 * 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 * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
133 static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
134                                ULONG, const void*, ULONG  );
135 static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
136 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
137 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
138 static LPVOID   (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
139 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
140 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
141 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
142 static LPVOID   (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
143 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
144 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
145
146 static HMODULE hntdll = 0;
147 static int CurrentTest = 0;
148 static UNICODE_STRING winetestpath;
149
150 #define NTDLL_GET_PROC(func) \
151     p ## func = (void*)GetProcAddress(hntdll, #func); \
152     if(!p ## func) { \
153         trace("GetProcAddress(%s) failed\n", #func); \
154         FreeLibrary(hntdll); \
155         return FALSE; \
156     }
157
158 static BOOL InitFunctionPtrs(void)
159 {
160     hntdll = LoadLibraryA("ntdll.dll");
161     if(!hntdll) {
162         trace("Could not load ntdll.dll\n");
163         return FALSE;
164     }
165     NTDLL_GET_PROC(RtlInitUnicodeString)
166     NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
167     NTDLL_GET_PROC(RtlCreateUnicodeString)
168     NTDLL_GET_PROC(RtlFreeUnicodeString)
169     NTDLL_GET_PROC(NtDeleteValueKey)
170     NTDLL_GET_PROC(RtlQueryRegistryValues)
171     NTDLL_GET_PROC(RtlCheckRegistryKey)
172     NTDLL_GET_PROC(RtlOpenCurrentUser)
173     NTDLL_GET_PROC(NtClose)
174     NTDLL_GET_PROC(NtDeleteValueKey)
175     NTDLL_GET_PROC(NtCreateKey)
176     NTDLL_GET_PROC(NtFlushKey)
177     NTDLL_GET_PROC(NtDeleteKey)
178     NTDLL_GET_PROC(NtQueryValueKey)
179     NTDLL_GET_PROC(NtQueryInformationProcess)
180     NTDLL_GET_PROC(NtSetValueKey)
181     NTDLL_GET_PROC(NtOpenKey)
182     NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
183     NTDLL_GET_PROC(RtlReAllocateHeap)
184     NTDLL_GET_PROC(RtlAppendUnicodeToString)
185     NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
186     NTDLL_GET_PROC(RtlFreeHeap)
187     NTDLL_GET_PROC(RtlAllocateHeap)
188     NTDLL_GET_PROC(RtlZeroMemory)
189     NTDLL_GET_PROC(RtlpNtQueryValueKey)
190     NTDLL_GET_PROC(RtlOpenCurrentUser)
191     return TRUE;
192 }
193 #undef NTDLL_GET_PROC
194
195 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
196                               IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
197 {
198     NTSTATUS ret = STATUS_SUCCESS;
199     int ValueNameLength = 0;
200     LPSTR ValName = 0;
201     trace("**Test %d**\n", CurrentTest);
202
203     if(ValueName)
204     {
205         ValueNameLength = lstrlenW(ValueName);
206
207         ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
208
209         WideCharToMultiByte(CP_ACP, 0, ValueName, ValueNameLength+1, ValName, ValueNameLength, NULL, NULL);
210
211         trace("ValueName: %s\n", ValName);
212     }
213     else
214         trace("ValueName: (null)\n");
215
216     switch(ValueType)
217     {
218             case REG_NONE:
219                 trace("ValueType: REG_NONE\n");
220                 trace("ValueData: %p\n", ValueData);
221                 break;
222
223             case REG_BINARY:
224                 trace("ValueType: REG_BINARY\n");
225                 trace("ValueData: %p\n", ValueData);
226                 break;
227
228             case REG_SZ:
229                 trace("ValueType: REG_SZ\n");
230                 trace("ValueData: %s\n", (char*)ValueData);
231                 break;
232
233             case REG_MULTI_SZ:
234                 trace("ValueType: REG_MULTI_SZ\n");
235                 trace("ValueData: %s\n", (char*)ValueData);
236                 break;
237
238             case REG_EXPAND_SZ:
239                 trace("ValueType: REG_EXPAND_SZ\n");
240                 trace("ValueData: %s\n", (char*)ValueData);
241                 break;
242
243             case REG_DWORD:
244                 trace("ValueType: REG_DWORD\n");
245                 trace("ValueData: %p\n", ValueData);
246                 break;
247     };
248     trace("ValueLength: %d\n", (int)ValueLength);
249
250     if(CurrentTest == 0)
251         ok(1, "\n"); /*checks that QueryRoutine is called*/
252     if(CurrentTest > 7)
253         ok(!1, "Invalid Test Specified!\n");
254
255     CurrentTest++;
256
257     if(ValName)
258         pRtlFreeHeap(GetProcessHeap(), 0, ValName);
259
260     return ret;
261 }
262
263 static void test_RtlQueryRegistryValues(void)
264 {
265
266     /*
267     ******************************
268     *       QueryTable Flags     *
269     ******************************
270     *RTL_QUERY_REGISTRY_SUBKEY   * Name is the name of a subkey relative to Path
271     *RTL_QUERY_REGISTRY_TOPKEY   * Resets location to original RelativeTo and Path
272     *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
273     *RTL_QUERY_REGISTRY_NOVALUE  * We just want a call-back
274     *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
275     *RTL_QUERY_REGISTRY_DIRECT   * Results of query will be stored in EntryContext(QueryRoutine ignored)
276     *RTL_QUERY_REGISTRY_DELETE   * Delete value key after query
277     ******************************
278
279
280     **Test layout(numbered according to CurrentTest value)**
281     0)NOVALUE           Just make sure call-back works
282     1)Null Name         See if QueryRoutine is called for every value in current key
283     2)SUBKEY            See if we can use SUBKEY to change the current path on the fly
284     3)REQUIRED          Test for value that's not there
285     4)NOEXPAND          See if it will return multiple strings(no expand should split strings up)
286     5)DIRECT            Make it store data directly in EntryContext and not call QueryRoutine
287     6)DefaultType       Test return values when key isn't present
288     7)DefaultValue      Test Default Value returned with key isn't present(and no REQUIRED flag set)
289     8)DefaultLength     Test Default Length with DefaultType = REG_SZ
290    9)DefaultLength      Test Default Length with DefaultType = REG_MULTI_SZ
291    10)DefaultLength     Test Default Length with DefaultType = REG_EXPAND_SZ
292    11)DefaultData       Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
293    12)Delete            Try to delete value key
294
295     */
296     NTSTATUS status;
297     ULONG RelativeTo;
298
299     PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
300     RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
301
302     QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
303
304     pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
305
306     QueryTable[0].QueryRoutine = QueryRoutine;
307     QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
308     QueryTable[0].Name = NULL;
309     QueryTable[0].EntryContext = NULL;
310     QueryTable[0].DefaultType = REG_BINARY;
311     QueryTable[0].DefaultData = NULL;
312     QueryTable[0].DefaultLength = 100;
313
314     QueryTable[1].QueryRoutine = QueryRoutine;
315     QueryTable[1].Flags = 0;
316     QueryTable[1].Name = NULL;
317     QueryTable[1].EntryContext = 0;
318     QueryTable[1].DefaultType = REG_NONE;
319     QueryTable[1].DefaultData = NULL;
320     QueryTable[1].DefaultLength = 0;
321
322     QueryTable[2].QueryRoutine = NULL;
323     QueryTable[2].Flags = 0;
324     QueryTable[2].Name = NULL;
325     QueryTable[2].EntryContext = 0;
326     QueryTable[2].DefaultType = REG_NONE;
327     QueryTable[2].DefaultData = NULL;
328     QueryTable[2].DefaultLength = 0;
329
330     status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
331     ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
332
333     pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
334 }
335
336 static void test_NtOpenKey(void)
337 {
338     HANDLE key;
339     NTSTATUS status;
340     OBJECT_ATTRIBUTES attr;
341     ACCESS_MASK am = KEY_READ;
342
343     /* All NULL */
344     status = pNtOpenKey(NULL, 0, NULL);
345     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
346
347     /* NULL attributes */
348     status = pNtOpenKey(&key, 0, NULL);
349     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
350         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
351
352     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
353
354     /* NULL key */
355     status = pNtOpenKey(NULL, am, &attr);
356     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
357
358     /* Length > sizeof(OBJECT_ATTRIBUTES) */
359     attr.Length *= 2;
360     status = pNtOpenKey(&key, am, &attr);
361     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
362 }
363
364 static void test_NtCreateKey(void)
365 {
366     /*Create WineTest*/
367     OBJECT_ATTRIBUTES attr;
368     HANDLE key, subkey;
369     ACCESS_MASK am = GENERIC_ALL;
370     NTSTATUS status;
371     UNICODE_STRING str;
372
373     /* All NULL */
374     status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
375     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
376        "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
377
378     /* Only the key */
379     status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
380     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
381         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
382
383     /* Only accessmask */
384     status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
385     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
386        "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
387
388     /* Key and accessmask */
389     status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
390     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
391         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
392
393     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
394
395     /* Only attributes */
396     status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
397     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
398        "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
399
400     /* Length > sizeof(OBJECT_ATTRIBUTES) */
401     attr.Length *= 2;
402     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
403     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
404
405     attr.Length = sizeof(attr);
406     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
407     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
408
409     attr.RootDirectory = key;
410     attr.ObjectName = &str;
411
412     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
413     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
414     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
415     pRtlFreeUnicodeString( &str );
416
417     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
418     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
419     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
420     pRtlFreeUnicodeString( &str );
421
422     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
423     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
424     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
425     pRtlFreeUnicodeString( &str );
426
427     pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
428     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
429     ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
430         "NtCreateKey failed: 0x%08x\n", status );
431     if (status == STATUS_SUCCESS)
432     {
433         pNtDeleteKey( subkey );
434         pNtClose( subkey );
435     }
436     pRtlFreeUnicodeString( &str );
437
438     pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
439     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
440     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
441     pRtlFreeUnicodeString( &str );
442     pNtDeleteKey( subkey );
443     pNtClose( subkey );
444
445     pNtClose(key);
446 }
447
448 static void test_NtSetValueKey(void)
449 {
450     HANDLE key;
451     NTSTATUS status;
452     OBJECT_ATTRIBUTES attr;
453     ACCESS_MASK am = KEY_WRITE;
454     UNICODE_STRING ValName;
455     DWORD data = 711;
456
457     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
458     status = pNtOpenKey(&key, am, &attr);
459     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
460
461     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
462     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
463     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
464     pRtlFreeUnicodeString(&ValName);
465
466     pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
467     status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
468     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
469     pRtlFreeUnicodeString(&ValName);
470
471     pNtClose(key);
472 }
473
474 static void test_RtlOpenCurrentUser(void)
475 {
476     NTSTATUS status;
477     HANDLE handle;
478     status=pRtlOpenCurrentUser(KEY_READ, &handle);
479     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
480     pNtClose(handle);
481 }
482
483 static void test_RtlCheckRegistryKey(void)
484 {
485     NTSTATUS status;
486
487     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
488     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
489
490     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
491     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
492 }
493
494 static void test_NtFlushKey(void)
495 {
496     NTSTATUS status;
497     HANDLE hkey;
498     OBJECT_ATTRIBUTES attr;
499     ACCESS_MASK am = KEY_ALL_ACCESS;
500
501     status = pNtFlushKey(NULL);
502     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
503
504     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
505     pNtOpenKey(&hkey, am, &attr);
506
507     status = pNtFlushKey(hkey);
508     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
509
510     pNtClose(hkey);
511 }
512
513 static void test_NtQueryValueKey(void)
514 {
515     HANDLE key;
516     NTSTATUS status;
517     OBJECT_ATTRIBUTES attr;
518     UNICODE_STRING ValName;
519     KEY_VALUE_BASIC_INFORMATION *basic_info;
520     KEY_VALUE_PARTIAL_INFORMATION *partial_info;
521     KEY_VALUE_FULL_INFORMATION *full_info;
522     DWORD len, expected;
523
524     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
525
526     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
527     status = pNtOpenKey(&key, KEY_READ, &attr);
528     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
529
530     len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
531     basic_info = HeapAlloc(GetProcessHeap(), 0, len);
532     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
533     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
534     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
535     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
536     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
537     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
538
539     basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
540     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
541     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
542     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
543     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
544     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
545     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
546     ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
547     HeapFree(GetProcessHeap(), 0, basic_info);
548
549     len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
550     partial_info = HeapAlloc(GetProcessHeap(), 0, len);
551     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
552     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
553     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
554     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
555     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
556     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
557
558     partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
559     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
560     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
561     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
562     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
563     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
564     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
565     ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
566     HeapFree(GetProcessHeap(), 0, partial_info);
567
568     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
569     full_info = HeapAlloc(GetProcessHeap(), 0, len);
570     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
571     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
572     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
573     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
574     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
575     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
576     ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
577         "NtQueryValueKey returned wrong len %d\n", len);
578     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
579
580     full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
581     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
582     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
583     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
584     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
585     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
586     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
587     ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
588     ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
589         *(DWORD *)((char *)full_info + full_info->DataOffset));
590     HeapFree(GetProcessHeap(), 0, full_info);
591
592     pRtlFreeUnicodeString(&ValName);
593     pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
594
595     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
596     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
597     partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
598     memset(partial_info, 0xbd, len+1);
599     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
600     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
601     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
602     ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
603     ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
604     ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
605     ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
606
607     expected = len;
608     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
609     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
610     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
611     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &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, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 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), &len);
618     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
619     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
620
621     HeapFree(GetProcessHeap(), 0, partial_info);
622
623     pRtlFreeUnicodeString(&ValName);
624     pNtClose(key);
625 }
626
627 static void test_NtDeleteKey(void)
628 {
629     NTSTATUS status;
630     HANDLE hkey;
631     OBJECT_ATTRIBUTES attr;
632     ACCESS_MASK am = KEY_ALL_ACCESS;
633
634     status = pNtDeleteKey(NULL);
635     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
636
637     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
638     status = pNtOpenKey(&hkey, am, &attr);
639     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
640
641     status = pNtDeleteKey(hkey);
642     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
643 }
644
645 static void test_RtlpNtQueryValueKey(void)
646 {
647     NTSTATUS status;
648
649     status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
650     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
651 }
652
653 static void test_symlinks(void)
654 {
655     static const WCHAR linkW[] = {'l','i','n','k',0};
656     static const WCHAR valueW[] = {'v','a','l','u','e',0};
657     static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
658     static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
659     static UNICODE_STRING null_str;
660     char buffer[1024];
661     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
662     WCHAR *target;
663     UNICODE_STRING symlink_str, link_str, target_str, value_str;
664     HANDLE root, key, link;
665     OBJECT_ATTRIBUTES attr;
666     NTSTATUS status;
667     DWORD target_len, len, dw;
668
669     pRtlInitUnicodeString( &link_str, linkW );
670     pRtlInitUnicodeString( &symlink_str, symlinkW );
671     pRtlInitUnicodeString( &target_str, targetW + 1 );
672     pRtlInitUnicodeString( &value_str, valueW );
673
674     target_len = winetestpath.Length + sizeof(targetW);
675     target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
676     memcpy( target, winetestpath.Buffer, winetestpath.Length );
677     memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
678
679     attr.Length = sizeof(attr);
680     attr.RootDirectory = 0;
681     attr.Attributes = 0;
682     attr.ObjectName = &winetestpath;
683     attr.SecurityDescriptor = NULL;
684     attr.SecurityQualityOfService = NULL;
685
686     status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
687     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
688
689     attr.RootDirectory = root;
690     attr.ObjectName = &link_str;
691     status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
692     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
693
694     /* REG_SZ is not allowed */
695     status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
696     ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
697     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
698     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
699     /* other values are not allowed */
700     status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
701     ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
702
703     /* try opening the target through the link */
704
705     attr.ObjectName = &link_str;
706     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
707     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
708
709     attr.ObjectName = &target_str;
710     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
711     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
712
713     dw = 0xbeef;
714     status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
715     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
716     pNtClose( key );
717
718     attr.ObjectName = &link_str;
719     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
720     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
721
722     len = sizeof(buffer);
723     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
724     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
725     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
726
727     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
728     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
729
730     /* REG_LINK can be created in non-link keys */
731     status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
732     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
733     len = sizeof(buffer);
734     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
735     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
736     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
737         "wrong len %u\n", len );
738     status = pNtDeleteValueKey( key, &symlink_str );
739     ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
740
741     pNtClose( key );
742
743     attr.Attributes = 0;
744     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
745     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
746
747     len = sizeof(buffer);
748     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
749     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
750     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
751
752     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
753     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
754     pNtClose( key );
755
756     /* now open the symlink itself */
757
758     attr.RootDirectory = root;
759     attr.Attributes = OBJ_OPENLINK;
760     attr.ObjectName = &link_str;
761     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
762     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
763
764     len = sizeof(buffer);
765     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
766     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
767     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
768         "wrong len %u\n", len );
769     pNtClose( key );
770
771     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
772     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
773     len = sizeof(buffer);
774     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
775     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
776     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
777         "wrong len %u\n", len );
778     pNtClose( key );
779
780     if (0)  /* crashes the Windows kernel on some Vista systems */
781     {
782         /* reopen the link from itself */
783
784         attr.RootDirectory = link;
785         attr.Attributes = OBJ_OPENLINK;
786         attr.ObjectName = &null_str;
787         status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
788         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
789         len = sizeof(buffer);
790         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
791         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
792         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
793             "wrong len %u\n", len );
794         pNtClose( key );
795
796         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
797         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
798         len = sizeof(buffer);
799         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
800         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
801         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
802             "wrong len %u\n", len );
803         pNtClose( key );
804     }
805
806     if (0)  /* crashes the Windows kernel in most versions */
807     {
808         attr.RootDirectory = link;
809         attr.Attributes = 0;
810         attr.ObjectName = &null_str;
811         status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
812         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
813         len = sizeof(buffer);
814         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
815         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
816         pNtClose( key );
817
818         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
819         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
820         len = sizeof(buffer);
821         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
822         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
823         pNtClose( key );
824     }
825
826     /* target with terminating null doesn't work */
827     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
828     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
829     attr.RootDirectory = root;
830     attr.Attributes = 0;
831     attr.ObjectName = &link_str;
832     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
833     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
834
835     /* relative symlink, works only on win2k */
836     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
837     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
838     attr.ObjectName = &link_str;
839     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
840     ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
841         "NtOpenKey wrong status 0x%08x\n", status );
842
843     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
844     ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
845
846     status = pNtDeleteKey( link );
847     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
848     pNtClose( link );
849
850     attr.ObjectName = &target_str;
851     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
852     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
853     status = pNtDeleteKey( key );
854     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
855     pNtClose( key );
856
857     /* symlink loop */
858
859     status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
860     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
861     memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
862     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
863         target, target_len + sizeof(targetW) - sizeof(WCHAR) );
864     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
865
866     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
867     ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
868         "NtOpenKey failed: 0x%08x\n", status );
869
870     attr.Attributes = OBJ_OPENLINK;
871     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
872     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
873     pNtClose( key );
874
875     status = pNtDeleteKey( link );
876     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
877     pNtClose( link );
878
879     status = pNtDeleteKey( root );
880     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
881     pNtClose( root );
882
883     pRtlFreeHeap(GetProcessHeap(), 0, target);
884 }
885
886 static WCHAR valueW[] = {'v','a','l','u','e'};
887 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
888 static const DWORD ptr_size = 8 * sizeof(void*);
889
890 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
891 {
892     char tmp[32];
893     NTSTATUS status;
894     OBJECT_ATTRIBUTES attr;
895     UNICODE_STRING str;
896     HANDLE key;
897     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
898     DWORD dw, len = sizeof(tmp);
899
900     attr.Length = sizeof(attr);
901     attr.RootDirectory = root;
902     attr.Attributes = OBJ_CASE_INSENSITIVE;
903     attr.ObjectName = &str;
904     attr.SecurityDescriptor = NULL;
905     attr.SecurityQualityOfService = NULL;
906     pRtlCreateUnicodeStringFromAsciiz( &str, name );
907
908     status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
909     if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
910     ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
911
912     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
913     if (status == STATUS_OBJECT_NAME_NOT_FOUND)
914         dw = 0;
915     else
916     {
917         ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
918         dw = *(DWORD *)info->Data;
919     }
920     pNtClose( key );
921     pRtlFreeUnicodeString( &str );
922     return dw;
923 }
924
925 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
926 {
927     DWORD dw = get_key_value( root, name, flags );
928     ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
929 }
930 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
931
932 static void test_redirection(void)
933 {
934     static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
935                                       'M','a','c','h','i','n','e','\\',
936                                       'S','o','f','t','w','a','r','e',0};
937     static const WCHAR wownodeW[] = {'\\','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','\\',
940                                      'W','o','w','6','4','3','2','N','o','d','e',0};
941     static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
942                                     'M','a','c','h','i','n','e','\\',
943                                     'S','o','f','t','w','a','r','e','\\',
944                                     'W','i','n','e',0};
945     static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
946                                     'M','a','c','h','i','n','e','\\',
947                                     'S','o','f','t','w','a','r','e','\\',
948                                     'W','o','w','6','4','3','2','N','o','d','e','\\',
949                                     'W','i','n','e',0};
950     static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
951                                    'M','a','c','h','i','n','e','\\',
952                                    'S','o','f','t','w','a','r','e','\\',
953                                    'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
954     static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
955                                    'M','a','c','h','i','n','e','\\',
956                                    'S','o','f','t','w','a','r','e','\\',
957                                    'W','o','w','6','4','3','2','N','o','d','e','\\',
958                                    'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
959     static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
960                                        'M','a','c','h','i','n','e','\\',
961                                        'S','o','f','t','w','a','r','e','\\',
962                                        'C','l','a','s','s','e','s','\\',
963                                        'W','i','n','e',0};
964     static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
965                                        'M','a','c','h','i','n','e','\\',
966                                        'S','o','f','t','w','a','r','e','\\',
967                                        'C','l','a','s','s','e','s','\\',
968                                        'W','o','w','6','4','3','2','N','o','d','e','\\',
969                                        'W','i','n','e',0};
970     NTSTATUS status;
971     OBJECT_ATTRIBUTES attr;
972     UNICODE_STRING str;
973     char buffer[1024];
974     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
975     DWORD dw, len;
976     HANDLE key, root32, root64, key32, key64;
977     BOOL is_vista = FALSE;
978
979     if (ptr_size != 64)
980     {
981         ULONG is_wow64, len;
982         if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
983                                         &is_wow64, sizeof(is_wow64), &len ) ||
984             !is_wow64)
985         {
986             trace( "Not on Wow64, no redirection\n" );
987             return;
988         }
989     }
990
991     attr.Length = sizeof(attr);
992     attr.RootDirectory = 0;
993     attr.Attributes = OBJ_CASE_INSENSITIVE;
994     attr.ObjectName = &str;
995     attr.SecurityDescriptor = NULL;
996     attr.SecurityQualityOfService = NULL;
997
998     pRtlInitUnicodeString( &str, wine64W );
999     status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1000     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1001
1002     pRtlInitUnicodeString( &str, wine32W );
1003     status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1004     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1005
1006     pRtlInitUnicodeString( &str, key64W );
1007     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1008     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1009
1010     pRtlInitUnicodeString( &str, key32W );
1011     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1012     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1013
1014     dw = 64;
1015     status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1016     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1017
1018     dw = 32;
1019     status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1020     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1021
1022     len = sizeof(buffer);
1023     status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1024     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1025     dw = *(DWORD *)info->Data;
1026     ok( dw == 32, "wrong value %u\n", dw );
1027
1028     len = sizeof(buffer);
1029     status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1030     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1031     dw = *(DWORD *)info->Data;
1032     ok( dw == 64, "wrong value %u\n", dw );
1033
1034     pRtlInitUnicodeString( &str, softwareW );
1035     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1036     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1037
1038     if (ptr_size == 32)
1039     {
1040         /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1041         /* the new (and simpler) Win7 mechanism doesn't */
1042         if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1043         {
1044             trace( "using Vista-style Wow6432Node handling\n" );
1045             is_vista = TRUE;
1046         }
1047         check_key_value( key, "Wine\\Winetest", 0, 32 );
1048         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1049         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1050         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1051         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1052         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1053     }
1054     else
1055     {
1056         check_key_value( key, "Wine\\Winetest", 0, 64 );
1057         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1058     }
1059     pNtClose( key );
1060
1061     if (ptr_size == 32)
1062     {
1063         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1064         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1065         dw = get_key_value( key, "Wine\\Winetest", 0 );
1066         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1067         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1068         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1069         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1070         dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1071         ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1072         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1073         pNtClose( key );
1074
1075         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1076         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1077         check_key_value( key, "Wine\\Winetest", 0, 32 );
1078         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1079         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1080         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1081         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1082         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1083         pNtClose( key );
1084     }
1085
1086     check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1087     check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1088     if (ptr_size == 64)
1089     {
1090         /* KEY_WOW64 flags have no effect on 64-bit */
1091         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1092         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1093         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1094         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1095     }
1096     else
1097     {
1098         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1099         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1100         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1101         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1102     }
1103
1104     pRtlInitUnicodeString( &str, wownodeW );
1105     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1106     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1107     check_key_value( key, "Wine\\Winetest", 0, 32 );
1108     check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1109     check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1110     pNtClose( key );
1111
1112     if (ptr_size == 32)
1113     {
1114         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1115         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1116         dw = get_key_value( key, "Wine\\Winetest", 0 );
1117         ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1118         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1119         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1120         pNtClose( key );
1121
1122         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1123         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1124         check_key_value( key, "Wine\\Winetest", 0, 32 );
1125         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1126         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1127         pNtClose( key );
1128     }
1129
1130     pRtlInitUnicodeString( &str, wine32W );
1131     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1132     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1133     check_key_value( key, "Winetest", 0, 32 );
1134     check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1135     check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1136     pNtClose( key );
1137
1138     if (ptr_size == 32)
1139     {
1140         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1141         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1142         dw = get_key_value( key, "Winetest", 0 );
1143         ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1144         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1145         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1146         pNtClose( key );
1147
1148         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1149         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1150         check_key_value( key, "Winetest", 0, 32 );
1151         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1152         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1153         pNtClose( key );
1154     }
1155
1156     pRtlInitUnicodeString( &str, wine64W );
1157     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1158     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1159     check_key_value( key, "Winetest", 0, ptr_size );
1160     check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1161     check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1162     pNtClose( key );
1163
1164     if (ptr_size == 32)
1165     {
1166         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1167         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1168         dw = get_key_value( key, "Winetest", 0 );
1169         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1170         check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1171         dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1172         todo_wine ok( dw == 32, "wrong value %u\n", dw );
1173         pNtClose( key );
1174
1175         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1176         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1177         check_key_value( key, "Winetest", 0, 32 );
1178         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1179         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1180         pNtClose( key );
1181     }
1182
1183     status = pNtDeleteKey( key32 );
1184     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1185     pNtClose( key32 );
1186
1187     status = pNtDeleteKey( key64 );
1188     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1189     pNtClose( key64 );
1190
1191     pNtDeleteKey( root32 );
1192     pNtClose( root32 );
1193     pNtDeleteKey( root64 );
1194     pNtClose( root64 );
1195
1196     /* Software\Classes is shared/reflected so behavior is different */
1197
1198     pRtlInitUnicodeString( &str, classes64W );
1199     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1200     if (status == STATUS_ACCESS_DENIED)
1201     {
1202         skip("Not authorized to modify the Classes key\n");
1203         return;
1204     }
1205     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1206
1207     pRtlInitUnicodeString( &str, classes32W );
1208     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1209     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1210
1211     dw = 64;
1212     status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1213     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1214     pNtClose( key64 );
1215
1216     dw = 32;
1217     status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1218     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1219     pNtClose( key32 );
1220
1221     pRtlInitUnicodeString( &str, classes64W );
1222     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1223     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1224     len = sizeof(buffer);
1225     status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1226     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1227     dw = *(DWORD *)info->Data;
1228     ok( dw == ptr_size, "wrong value %u\n", dw );
1229
1230     pRtlInitUnicodeString( &str, classes32W );
1231     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1232     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1233     len = sizeof(buffer);
1234     status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1235     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1236     dw = *(DWORD *)info->Data;
1237     ok( dw == 32, "wrong value %u\n", dw );
1238
1239     pNtDeleteKey( key32 );
1240     pNtClose( key32 );
1241     pNtDeleteKey( key64 );
1242     pNtClose( key64 );
1243 }
1244
1245 static void test_long_value_name(void)
1246 {
1247     HANDLE key;
1248     NTSTATUS status, expected;
1249     OBJECT_ATTRIBUTES attr;
1250     UNICODE_STRING ValName;
1251     DWORD i;
1252
1253     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1254     status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1255     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1256
1257     ValName.MaximumLength = 0xfffc;
1258     ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1259     ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1260     for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1261         ValName.Buffer[i] = 'a';
1262     ValName.Buffer[i] = 0;
1263
1264     status = pNtDeleteValueKey(key, &ValName);
1265     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1266     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1267     ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1268        "NtSetValueKey with long value name returned 0x%08x\n", status);
1269     expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1270     status = pNtDeleteValueKey(key, &ValName);
1271     ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1272
1273     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1274     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1275
1276     pRtlFreeUnicodeString(&ValName);
1277     pNtClose(key);
1278 }
1279
1280 START_TEST(reg)
1281 {
1282     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1283     if(!InitFunctionPtrs())
1284         return;
1285     pRtlFormatCurrentUserKeyPath(&winetestpath);
1286     winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1287                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1288     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1289
1290     pRtlAppendUnicodeToString(&winetestpath, winetest);
1291
1292     test_NtCreateKey();
1293     test_NtOpenKey();
1294     test_NtSetValueKey();
1295     test_RtlCheckRegistryKey();
1296     test_RtlOpenCurrentUser();
1297     test_RtlQueryRegistryValues();
1298     test_RtlpNtQueryValueKey();
1299     test_NtFlushKey();
1300     test_NtQueryValueKey();
1301     test_long_value_name();
1302     test_NtDeleteKey();
1303     test_symlinks();
1304     test_redirection();
1305
1306     pRtlFreeUnicodeString(&winetestpath);
1307
1308     FreeLibrary(hntdll);
1309 }