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