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