xref: /reactos/modules/rostests/winetests/ntdll/reg.c (revision c2c66aff)
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 "wine/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 BOOLEAN  (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
119 static void     (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
120 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
121 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
122 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
123 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
124 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE);
125 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
126 static NTSTATUS (WINAPI * pNtOpenKeyEx)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG);
127 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
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 * pNtQueryKey)(HANDLE,KEY_INFORMATION_CLASS,PVOID,ULONG,PULONG);
134 static NTSTATUS (WINAPI * pNtQueryLicenseValue)(const UNICODE_STRING *,ULONG *,PVOID,ULONG,ULONG *);
135 static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
136 static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
137                                ULONG, const void*, ULONG  );
138 static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
139 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
140 static LONG     (WINAPI * pRtlCompareUnicodeString)(const PUNICODE_STRING,const PUNICODE_STRING,BOOLEAN);
141 static BOOLEAN  (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR);
142 static LPVOID   (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
143 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
144 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
145 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
146 static LPVOID   (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
147 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
148 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
149 static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN);
150 static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE,
151                                                        void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN);
152 static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*);
153 
154 static HMODULE hntdll = 0;
155 static int CurrentTest = 0;
156 static UNICODE_STRING winetestpath;
157 
158 #define NTDLL_GET_PROC(func) \
159     p ## func = (void*)GetProcAddress(hntdll, #func); \
160     if(!p ## func) { \
161         trace("GetProcAddress(%s) failed\n", #func); \
162         FreeLibrary(hntdll); \
163         return FALSE; \
164     }
165 
166 static BOOL InitFunctionPtrs(void)
167 {
168     hntdll = LoadLibraryA("ntdll.dll");
169     if(!hntdll) {
170         trace("Could not load ntdll.dll\n");
171         return FALSE;
172     }
173     NTDLL_GET_PROC(RtlInitUnicodeString)
174     NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
175     NTDLL_GET_PROC(RtlCreateUnicodeString)
176     NTDLL_GET_PROC(RtlFreeUnicodeString)
177     NTDLL_GET_PROC(RtlQueryRegistryValues)
178     NTDLL_GET_PROC(RtlCheckRegistryKey)
179     NTDLL_GET_PROC(RtlOpenCurrentUser)
180     NTDLL_GET_PROC(NtClose)
181     NTDLL_GET_PROC(NtDeleteValueKey)
182     NTDLL_GET_PROC(NtCreateKey)
183     NTDLL_GET_PROC(NtFlushKey)
184     NTDLL_GET_PROC(NtDeleteKey)
185     NTDLL_GET_PROC(NtQueryKey)
186     NTDLL_GET_PROC(NtQueryValueKey)
187     NTDLL_GET_PROC(NtQueryInformationProcess)
188     NTDLL_GET_PROC(NtSetValueKey)
189     NTDLL_GET_PROC(NtOpenKey)
190     NTDLL_GET_PROC(NtNotifyChangeKey)
191     NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
192     NTDLL_GET_PROC(RtlCompareUnicodeString)
193     NTDLL_GET_PROC(RtlReAllocateHeap)
194     NTDLL_GET_PROC(RtlAppendUnicodeToString)
195     NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
196     NTDLL_GET_PROC(RtlFreeHeap)
197     NTDLL_GET_PROC(RtlAllocateHeap)
198     NTDLL_GET_PROC(RtlZeroMemory)
199     NTDLL_GET_PROC(RtlpNtQueryValueKey)
200     NTDLL_GET_PROC(RtlOpenCurrentUser)
201     NTDLL_GET_PROC(NtWaitForSingleObject)
202 
203     /* optional functions */
204     pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue");
205     pNtOpenKeyEx = (void *)GetProcAddress(hntdll, "NtOpenKeyEx");
206     pNtNotifyChangeMultipleKeys = (void *)GetProcAddress(hntdll, "NtNotifyChangeMultipleKeys");
207 
208     return TRUE;
209 }
210 #undef NTDLL_GET_PROC
211 
212 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
213                               IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
214 {
215     NTSTATUS ret = STATUS_SUCCESS;
216 
217     trace("**Test %d**\n", CurrentTest);
218     trace("ValueName: %s\n", wine_dbgstr_w(ValueName));
219 
220     switch(ValueType)
221     {
222             case REG_NONE:
223                 trace("ValueType: REG_NONE\n");
224                 trace("ValueData: %p\n", ValueData);
225                 break;
226 
227             case REG_BINARY:
228                 trace("ValueType: REG_BINARY\n");
229                 trace("ValueData: %p\n", ValueData);
230                 break;
231 
232             case REG_SZ:
233                 trace("ValueType: REG_SZ\n");
234                 trace("ValueData: %s\n", (char*)ValueData);
235                 break;
236 
237             case REG_MULTI_SZ:
238                 trace("ValueType: REG_MULTI_SZ\n");
239                 trace("ValueData: %s\n", (char*)ValueData);
240                 break;
241 
242             case REG_EXPAND_SZ:
243                 trace("ValueType: REG_EXPAND_SZ\n");
244                 trace("ValueData: %s\n", (char*)ValueData);
245                 break;
246 
247             case REG_DWORD:
248                 trace("ValueType: REG_DWORD\n");
249                 trace("ValueData: %p\n", ValueData);
250                 break;
251     };
252     trace("ValueLength: %d\n", (int)ValueLength);
253 
254     if(CurrentTest == 0)
255         ok(1, "\n"); /*checks that QueryRoutine is called*/
256     if(CurrentTest > 7)
257         ok(!1, "Invalid Test Specified!\n");
258 
259     CurrentTest++;
260 
261     return ret;
262 }
263 
264 static void test_RtlQueryRegistryValues(void)
265 {
266 
267     /*
268     ******************************
269     *       QueryTable Flags     *
270     ******************************
271     *RTL_QUERY_REGISTRY_SUBKEY   * Name is the name of a subkey relative to Path
272     *RTL_QUERY_REGISTRY_TOPKEY   * Resets location to original RelativeTo and Path
273     *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
274     *RTL_QUERY_REGISTRY_NOVALUE  * We just want a call-back
275     *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
276     *RTL_QUERY_REGISTRY_DIRECT   * Results of query will be stored in EntryContext(QueryRoutine ignored)
277     *RTL_QUERY_REGISTRY_DELETE   * Delete value key after query
278     ******************************
279 
280 
281     **Test layout(numbered according to CurrentTest value)**
282     0)NOVALUE           Just make sure call-back works
283     1)Null Name         See if QueryRoutine is called for every value in current key
284     2)SUBKEY            See if we can use SUBKEY to change the current path on the fly
285     3)REQUIRED          Test for value that's not there
286     4)NOEXPAND          See if it will return multiple strings(no expand should split strings up)
287     5)DIRECT            Make it store data directly in EntryContext and not call QueryRoutine
288     6)DefaultType       Test return values when key isn't present
289     7)DefaultValue      Test Default Value returned with key isn't present(and no REQUIRED flag set)
290     8)DefaultLength     Test Default Length with DefaultType = REG_SZ
291    9)DefaultLength      Test Default Length with DefaultType = REG_MULTI_SZ
292    10)DefaultLength     Test Default Length with DefaultType = REG_EXPAND_SZ
293    11)DefaultData       Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
294    12)Delete            Try to delete value key
295 
296     */
297     NTSTATUS status;
298     ULONG RelativeTo;
299 
300     PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
301     RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
302 
303     QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
304 
305     pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
306 
307     QueryTable[0].QueryRoutine = QueryRoutine;
308     QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
309     QueryTable[0].Name = NULL;
310     QueryTable[0].EntryContext = NULL;
311     QueryTable[0].DefaultType = REG_BINARY;
312     QueryTable[0].DefaultData = NULL;
313     QueryTable[0].DefaultLength = 100;
314 
315     QueryTable[1].QueryRoutine = QueryRoutine;
316     QueryTable[1].Flags = 0;
317     QueryTable[1].Name = NULL;
318     QueryTable[1].EntryContext = 0;
319     QueryTable[1].DefaultType = REG_NONE;
320     QueryTable[1].DefaultData = NULL;
321     QueryTable[1].DefaultLength = 0;
322 
323     QueryTable[2].QueryRoutine = NULL;
324     QueryTable[2].Flags = 0;
325     QueryTable[2].Name = NULL;
326     QueryTable[2].EntryContext = 0;
327     QueryTable[2].DefaultType = REG_NONE;
328     QueryTable[2].DefaultData = NULL;
329     QueryTable[2].DefaultLength = 0;
330 
331     status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
332     ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
333 
334     pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
335 }
336 
337 static void test_NtOpenKey(void)
338 {
339     HANDLE key;
340     NTSTATUS status;
341     OBJECT_ATTRIBUTES attr;
342     ACCESS_MASK am = KEY_READ;
343     UNICODE_STRING str;
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     /* Zero accessmask */
366     attr.Length = sizeof(attr);
367     status = pNtOpenKey(&key, 0, &attr);
368 todo_wine
369     ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
370     if (status == STATUS_SUCCESS) NtClose(key);
371 
372     /* Calling without parent key requres full registry path. */
373     pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
374     InitializeObjectAttributes(&attr, &str, 0, 0, 0);
375     status = pNtOpenKey(&key, KEY_READ, &attr);
376     todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
377     pRtlFreeUnicodeString( &str );
378 
379     /* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
380     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine" );
381     status = pNtOpenKey(&key, KEY_READ, &attr);
382     todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey Failed: 0x%08x\n", status);
383 
384     attr.Attributes = OBJ_CASE_INSENSITIVE;
385     status = pNtOpenKey(&key, KEY_READ, &attr);
386     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
387     pNtClose(key);
388     pRtlFreeUnicodeString( &str );
389 
390     pRtlCreateUnicodeStringFromAsciiz( &str, "" );
391     status = pNtOpenKey(&key, KEY_READ, &attr);
392     todo_wine
393     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
394     pRtlFreeUnicodeString( &str );
395 
396     pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
397     status = pNtOpenKey(&key, KEY_READ, &attr);
398     todo_wine
399     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
400     pRtlFreeUnicodeString( &str );
401 
402     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
403     status = pNtOpenKey(&key, KEY_READ, &attr);
404     todo_wine
405     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
406     pNtClose( key );
407     pRtlFreeUnicodeString( &str );
408 
409     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
410     status = pNtOpenKey(&key, KEY_READ, &attr);
411     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
412     pNtClose( key );
413     pRtlFreeUnicodeString( &str );
414 
415     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
416     status = pNtOpenKey(&key, KEY_READ, &attr);
417     todo_wine
418     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
419     pRtlFreeUnicodeString( &str );
420 
421     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
422     status = pNtOpenKey(&key, KEY_READ, &attr);
423     todo_wine
424     ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
425     pRtlFreeUnicodeString( &str );
426 
427     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
428     status = pNtOpenKey(&key, KEY_READ, &attr);
429     todo_wine
430     ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
431     pRtlFreeUnicodeString( &str );
432 
433     pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
434     status = pNtOpenKey(&key, KEY_READ, &attr);
435     todo_wine
436     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
437     pRtlFreeUnicodeString( &str );
438 
439     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
440     status = pNtOpenKey(&key, KEY_READ, &attr);
441     todo_wine
442     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
443     pRtlFreeUnicodeString( &str );
444 
445     if (!pNtOpenKeyEx)
446     {
447         win_skip("NtOpenKeyEx not available\n");
448         return;
449     }
450 
451     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
452     status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0);
453     ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status);
454 
455     pNtClose(key);
456 }
457 
458 static void test_NtCreateKey(void)
459 {
460     /*Create WineTest*/
461     OBJECT_ATTRIBUTES attr;
462     HANDLE key, subkey;
463     ACCESS_MASK am = GENERIC_ALL;
464     NTSTATUS status;
465     UNICODE_STRING str;
466 
467     /* All NULL */
468     status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
469     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
470        "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
471 
472     /* Only the key */
473     status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
474     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
475         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
476 
477     /* Only accessmask */
478     status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
479     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
480        "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
481 
482     /* Key and accessmask */
483     status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
484     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
485         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
486 
487     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
488 
489     /* Only attributes */
490     status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
491     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
492        "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
493 
494     /* Length > sizeof(OBJECT_ATTRIBUTES) */
495     attr.Length *= 2;
496     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
497     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
498 
499     attr.Length = sizeof(attr);
500     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
501     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
502 
503     attr.RootDirectory = key;
504     attr.ObjectName = &str;
505 
506     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
507     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
508     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
509     pRtlFreeUnicodeString( &str );
510 
511     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
512     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
513     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
514     pRtlFreeUnicodeString( &str );
515 
516     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
517     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
518     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
519     pRtlFreeUnicodeString( &str );
520 
521     pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
522     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
523     ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
524         "NtCreateKey failed: 0x%08x\n", status );
525     if (status == STATUS_SUCCESS)
526     {
527         pNtDeleteKey( subkey );
528         pNtClose( subkey );
529     }
530     pRtlFreeUnicodeString( &str );
531 
532     pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
533     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
534     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
535     pRtlFreeUnicodeString( &str );
536     pNtDeleteKey( subkey );
537     pNtClose( subkey );
538 
539     attr.RootDirectory = 0;
540     attr.Attributes = OBJ_CASE_INSENSITIVE;
541 
542     pRtlCreateUnicodeStringFromAsciiz( &str, "" );
543     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
544     todo_wine
545     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
546     pRtlFreeUnicodeString( &str );
547 
548     pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
549     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
550     todo_wine
551     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
552     pRtlFreeUnicodeString( &str );
553 
554     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
555     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
556     todo_wine
557     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
558         "NtCreateKey failed: 0x%08x\n", status );
559     if (!status) pNtClose( subkey );
560     pRtlFreeUnicodeString( &str );
561 
562     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
563     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
564     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
565         "NtCreateKey failed: 0x%08x\n", status );
566     if (!status) pNtClose( subkey );
567     pRtlFreeUnicodeString( &str );
568 
569     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
570     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
571     todo_wine
572     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
573     pRtlFreeUnicodeString( &str );
574 
575     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
576     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
577     todo_wine
578     ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
579     pRtlFreeUnicodeString( &str );
580 
581     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
582     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
583     todo_wine
584     ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
585     pRtlFreeUnicodeString( &str );
586 
587     pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
588     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
589     todo_wine
590     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
591     pRtlFreeUnicodeString( &str );
592 
593     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
594     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
595     todo_wine
596     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
597     pRtlFreeUnicodeString( &str );
598 
599     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
600     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
601     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
602         "NtCreateKey failed: 0x%08x\n", status );
603     if (!status) pNtClose( subkey );
604     pRtlFreeUnicodeString( &str );
605 
606     /* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */
607     attr.Attributes = 0;
608     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
609     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
610     todo_wine
611     ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
612     pRtlFreeUnicodeString( &str );
613 
614     pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\Machine\\Software\\Classes" );
615     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
616     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
617         "NtCreateKey failed: 0x%08x\n", status );
618     if (!status) pNtClose( subkey );
619     pRtlFreeUnicodeString( &str );
620 
621     pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" );
622     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
623     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
624         "NtCreateKey failed: 0x%08x\n", status );
625     if (!status) pNtClose( subkey );
626     pRtlFreeUnicodeString( &str );
627 
628     pNtClose(key);
629 }
630 
631 static void test_NtSetValueKey(void)
632 {
633     HANDLE key;
634     NTSTATUS status;
635     OBJECT_ATTRIBUTES attr;
636     ACCESS_MASK am = KEY_WRITE;
637     UNICODE_STRING ValName;
638     DWORD data = 711;
639 
640     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
641     status = pNtOpenKey(&key, am, &attr);
642     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
643 
644     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
645     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
646     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
647     pRtlFreeUnicodeString(&ValName);
648 
649     pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
650     status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
651     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
652     pRtlFreeUnicodeString(&ValName);
653 
654     pNtClose(key);
655 }
656 
657 static void test_RtlOpenCurrentUser(void)
658 {
659     NTSTATUS status;
660     HANDLE handle;
661     status=pRtlOpenCurrentUser(KEY_READ, &handle);
662     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
663     pNtClose(handle);
664 }
665 
666 static void test_RtlCheckRegistryKey(void)
667 {
668     NTSTATUS status;
669 
670     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
671     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
672 
673     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
674     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
675 }
676 
677 static void test_NtFlushKey(void)
678 {
679     NTSTATUS status;
680     HANDLE hkey;
681     OBJECT_ATTRIBUTES attr;
682     ACCESS_MASK am = KEY_ALL_ACCESS;
683 
684     status = pNtFlushKey(NULL);
685     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
686 
687     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
688     pNtOpenKey(&hkey, am, &attr);
689 
690     status = pNtFlushKey(hkey);
691     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
692 
693     pNtClose(hkey);
694 }
695 
696 static void test_NtQueryValueKey(void)
697 {
698     HANDLE key;
699     NTSTATUS status;
700     OBJECT_ATTRIBUTES attr;
701     UNICODE_STRING ValName;
702     KEY_VALUE_BASIC_INFORMATION *basic_info;
703     KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi;
704     KEY_VALUE_FULL_INFORMATION *full_info;
705     DWORD len, expected;
706 
707     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
708 
709     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
710     status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr);
711     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
712 
713     len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
714     basic_info = HeapAlloc(GetProcessHeap(), 0, len);
715     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
716     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
717     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
718     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
719     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
720     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
721 
722     basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
723     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
724     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
725     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
726     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
727     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
728     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
729     ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
730     HeapFree(GetProcessHeap(), 0, basic_info);
731 
732     len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
733     partial_info = HeapAlloc(GetProcessHeap(), 0, len);
734     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
735     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
736     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
737     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
738     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
739     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
740 
741     partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
742     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
743     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
744     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
745     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
746     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
747     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
748     ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
749     HeapFree(GetProcessHeap(), 0, partial_info);
750 
751     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
752     full_info = HeapAlloc(GetProcessHeap(), 0, len);
753     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
754     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
755     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
756     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
757     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
758     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
759     ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
760         "NtQueryValueKey returned wrong len %d\n", len);
761     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
762 
763     full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
764     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
765     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
766     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
767     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
768     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
769     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
770     ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
771     ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
772         *(DWORD *)((char *)full_info + full_info->DataOffset));
773     HeapFree(GetProcessHeap(), 0, full_info);
774 
775     pRtlFreeUnicodeString(&ValName);
776     pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
777 
778     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
779     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
780     partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
781     memset(partial_info, 0xbd, len+1);
782     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
783     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
784     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
785     ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
786     ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
787     ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
788     ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
789 
790     expected = len;
791     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
792     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
793     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
794     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
795     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
796     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
797     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
798     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
799     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
800     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
801     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
802     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
803 
804     HeapFree(GetProcessHeap(), 0, partial_info);
805     pRtlFreeUnicodeString(&ValName);
806 
807     pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest");
808     status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0);
809     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
810 
811     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
812     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
813     ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type);
814     ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength);
815     pRtlFreeUnicodeString(&ValName);
816 
817     pNtClose(key);
818 }
819 
820 static void test_NtDeleteKey(void)
821 {
822     NTSTATUS status;
823     HANDLE hkey;
824     OBJECT_ATTRIBUTES attr;
825     ACCESS_MASK am = KEY_ALL_ACCESS;
826 
827     status = pNtDeleteKey(NULL);
828     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
829 
830     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
831     status = pNtOpenKey(&hkey, am, &attr);
832     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
833 
834     status = pNtDeleteKey(hkey);
835     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
836 }
837 
838 static void test_NtQueryLicenseKey(void)
839 {
840     static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
841     UNICODE_STRING name;
842     WORD buffer[32];
843     NTSTATUS status;
844     ULONG type, len;
845     DWORD value;
846 
847     if (!pNtQueryLicenseValue)
848     {
849         win_skip("NtQueryLicenseValue not found, skipping tests\n");
850         return;
851     }
852 
853     type = 0xdead;
854     len = 0xbeef;
855     memset(&name, 0, sizeof(name));
856     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
857     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
858     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
859     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
860 
861     /* test with empty key */
862     pRtlCreateUnicodeStringFromAsciiz(&name, "");
863 
864     type = 0xdead;
865     len = 0xbeef;
866     status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
867     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
868     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
869     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
870 
871     type = 0xdead;
872     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
873     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
874     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
875 
876     len = 0xbeef;
877     status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
878     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
879     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
880 
881     type = 0xdead;
882     len = 0xbeef;
883     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
884     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
885     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
886     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
887 
888     pRtlFreeUnicodeString(&name);
889 
890     /* test with nonexistent licence key */
891     pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
892 
893     type = 0xdead;
894     len = 0xbeef;
895     status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
896     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
897     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
898     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
899 
900     type = 0xdead;
901     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
902     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
903     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
904 
905     len = 0xbeef;
906     status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
907     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
908     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
909 
910     type = 0xdead;
911     len = 0xbeef;
912     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
913     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n");
914     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
915     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
916 
917     pRtlFreeUnicodeString(&name);
918 
919     /* test with REG_SZ license key */
920     pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
921 
922     type = 0xdead;
923     len = 0xbeef;
924     status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
925     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
926     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
927     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
928 
929     type = 0xdead;
930     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
931     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
932     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
933 
934     type = 0xdead;
935     len = 0;
936     status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
937     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
938     ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
939     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
940 
941     len = 0;
942     status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
943     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
944     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
945 
946     type = 0xdead;
947     len = 0;
948     memset(buffer, 0x11, sizeof(buffer));
949     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
950     ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
951     ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
952     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
953     ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
954 
955     type = 0xdead;
956     len = 0;
957     memset(buffer, 0x11, sizeof(buffer));
958     status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
959     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
960     ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
961     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
962     ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
963 
964     pRtlFreeUnicodeString(&name);
965 
966     /* test with REG_DWORD license key */
967     pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
968 
969     type = 0xdead;
970     len = 0xbeef;
971     status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
972     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
973     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
974     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
975 
976     type = 0xdead;
977     status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
978     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
979     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
980 
981     type = 0xdead;
982     len = 0;
983     status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
984     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
985     ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
986     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
987 
988     len = 0;
989     status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
990     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
991     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
992 
993     type = 0xdead;
994     len = 0;
995     value = 0xdeadbeef;
996     status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
997     ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
998     ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
999     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1000     ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
1001 
1002     type = 0xdead;
1003     len = 0;
1004     status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
1005     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
1006     ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
1007     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1008 
1009     pRtlFreeUnicodeString(&name);
1010 }
1011 
1012 static void test_RtlpNtQueryValueKey(void)
1013 {
1014     NTSTATUS status;
1015 
1016     status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
1017     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
1018 }
1019 
1020 static void test_symlinks(void)
1021 {
1022     static const WCHAR linkW[] = {'l','i','n','k',0};
1023     static const WCHAR valueW[] = {'v','a','l','u','e',0};
1024     static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
1025     static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
1026     static UNICODE_STRING null_str;
1027     char buffer[1024];
1028     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1029     WCHAR *target;
1030     UNICODE_STRING symlink_str, link_str, target_str, value_str;
1031     HANDLE root, key, link;
1032     OBJECT_ATTRIBUTES attr;
1033     NTSTATUS status;
1034     DWORD target_len, len, dw;
1035 
1036     pRtlInitUnicodeString( &link_str, linkW );
1037     pRtlInitUnicodeString( &symlink_str, symlinkW );
1038     pRtlInitUnicodeString( &target_str, targetW + 1 );
1039     pRtlInitUnicodeString( &value_str, valueW );
1040 
1041     target_len = winetestpath.Length + sizeof(targetW);
1042     target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
1043     memcpy( target, winetestpath.Buffer, winetestpath.Length );
1044     memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
1045 
1046     attr.Length = sizeof(attr);
1047     attr.RootDirectory = 0;
1048     attr.Attributes = 0;
1049     attr.ObjectName = &winetestpath;
1050     attr.SecurityDescriptor = NULL;
1051     attr.SecurityQualityOfService = NULL;
1052 
1053     status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1054     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1055 
1056     attr.RootDirectory = root;
1057     attr.ObjectName = &link_str;
1058     status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1059     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1060 
1061     /* REG_SZ is not allowed */
1062     status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
1063     ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1064     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1065     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1066     /* other values are not allowed */
1067     status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1068     ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1069 
1070     /* try opening the target through the link */
1071 
1072     attr.ObjectName = &link_str;
1073     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1074     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1075 
1076     attr.ObjectName = &target_str;
1077     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1078     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1079 
1080     dw = 0xbeef;
1081     status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1082     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1083     pNtClose( key );
1084 
1085     attr.ObjectName = &link_str;
1086     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1087     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1088 
1089     len = sizeof(buffer);
1090     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1091     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1092     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1093 
1094     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1095     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1096 
1097     /* REG_LINK can be created in non-link keys */
1098     status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1099     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1100     len = sizeof(buffer);
1101     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1102     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1103     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1104         "wrong len %u\n", len );
1105     status = pNtDeleteValueKey( key, &symlink_str );
1106     ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
1107 
1108     pNtClose( key );
1109 
1110     attr.Attributes = 0;
1111     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1112     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1113 
1114     len = sizeof(buffer);
1115     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1116     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1117     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1118 
1119     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1120     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1121     pNtClose( key );
1122 
1123     /* now open the symlink itself */
1124 
1125     attr.RootDirectory = root;
1126     attr.Attributes = OBJ_OPENLINK;
1127     attr.ObjectName = &link_str;
1128     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1129     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1130 
1131     len = sizeof(buffer);
1132     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1133     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1134     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1135         "wrong len %u\n", len );
1136     pNtClose( key );
1137 
1138     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1139     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1140     len = sizeof(buffer);
1141     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1142     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1143     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1144         "wrong len %u\n", len );
1145     pNtClose( key );
1146 
1147     if (0)  /* crashes the Windows kernel on some Vista systems */
1148     {
1149         /* reopen the link from itself */
1150 
1151         attr.RootDirectory = link;
1152         attr.Attributes = OBJ_OPENLINK;
1153         attr.ObjectName = &null_str;
1154         status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1155         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1156         len = sizeof(buffer);
1157         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1158         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1159         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1160             "wrong len %u\n", len );
1161         pNtClose( key );
1162 
1163         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1164         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1165         len = sizeof(buffer);
1166         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1167         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1168         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1169             "wrong len %u\n", len );
1170         pNtClose( key );
1171     }
1172 
1173     if (0)  /* crashes the Windows kernel in most versions */
1174     {
1175         attr.RootDirectory = link;
1176         attr.Attributes = 0;
1177         attr.ObjectName = &null_str;
1178         status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1179         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1180         len = sizeof(buffer);
1181         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1182         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1183         pNtClose( key );
1184 
1185         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1186         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1187         len = sizeof(buffer);
1188         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1189         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1190         pNtClose( key );
1191     }
1192 
1193     /* target with terminating null doesn't work */
1194     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
1195     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1196     attr.RootDirectory = root;
1197     attr.Attributes = 0;
1198     attr.ObjectName = &link_str;
1199     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1200     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1201 
1202     /* relative symlink, works only on win2k */
1203     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
1204     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1205     attr.ObjectName = &link_str;
1206     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1207     ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
1208         "NtOpenKey wrong status 0x%08x\n", status );
1209 
1210     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1211     ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
1212 
1213     status = pNtDeleteKey( link );
1214     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1215     pNtClose( link );
1216 
1217     attr.ObjectName = &target_str;
1218     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1219     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1220     status = pNtDeleteKey( key );
1221     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1222     pNtClose( key );
1223 
1224     /* symlink loop */
1225 
1226     status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1227     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1228     memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
1229     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
1230         target, target_len + sizeof(targetW) - sizeof(WCHAR) );
1231     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1232 
1233     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1234     ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
1235         "NtOpenKey failed: 0x%08x\n", status );
1236 
1237     attr.Attributes = OBJ_OPENLINK;
1238     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1239     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1240     pNtClose( key );
1241 
1242     status = pNtDeleteKey( link );
1243     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1244     pNtClose( link );
1245 
1246     status = pNtDeleteKey( root );
1247     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1248     pNtClose( root );
1249 
1250     pRtlFreeHeap(GetProcessHeap(), 0, target);
1251 }
1252 
1253 static WCHAR valueW[] = {'v','a','l','u','e'};
1254 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
1255 static const DWORD ptr_size = 8 * sizeof(void*);
1256 
1257 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
1258 {
1259     char tmp[32];
1260     NTSTATUS status;
1261     OBJECT_ATTRIBUTES attr;
1262     UNICODE_STRING str;
1263     HANDLE key;
1264     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
1265     DWORD dw, len = sizeof(tmp);
1266 
1267     attr.Length = sizeof(attr);
1268     attr.RootDirectory = root;
1269     attr.Attributes = OBJ_CASE_INSENSITIVE;
1270     attr.ObjectName = &str;
1271     attr.SecurityDescriptor = NULL;
1272     attr.SecurityQualityOfService = NULL;
1273     pRtlCreateUnicodeStringFromAsciiz( &str, name );
1274 
1275     status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1276     if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
1277     ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
1278 
1279     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1280     if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1281         dw = 0;
1282     else
1283     {
1284         ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
1285         dw = *(DWORD *)info->Data;
1286     }
1287     pNtClose( key );
1288     pRtlFreeUnicodeString( &str );
1289     return dw;
1290 }
1291 
1292 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
1293 {
1294     DWORD dw = get_key_value( root, name, flags );
1295     ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
1296 }
1297 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
1298 
1299 static void test_redirection(void)
1300 {
1301     static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1302                                       'M','a','c','h','i','n','e','\\',
1303                                       'S','o','f','t','w','a','r','e',0};
1304     static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1305                                      'M','a','c','h','i','n','e','\\',
1306                                      'S','o','f','t','w','a','r','e','\\',
1307                                      'W','o','w','6','4','3','2','N','o','d','e',0};
1308     static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1309                                     'M','a','c','h','i','n','e','\\',
1310                                     'S','o','f','t','w','a','r','e','\\',
1311                                     'W','i','n','e',0};
1312     static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1313                                     'M','a','c','h','i','n','e','\\',
1314                                     'S','o','f','t','w','a','r','e','\\',
1315                                     'W','o','w','6','4','3','2','N','o','d','e','\\',
1316                                     'W','i','n','e',0};
1317     static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1318                                    'M','a','c','h','i','n','e','\\',
1319                                    'S','o','f','t','w','a','r','e','\\',
1320                                    'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
1321     static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1322                                    'M','a','c','h','i','n','e','\\',
1323                                    'S','o','f','t','w','a','r','e','\\',
1324                                    'W','o','w','6','4','3','2','N','o','d','e','\\',
1325                                    'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
1326     static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1327                                        'M','a','c','h','i','n','e','\\',
1328                                        'S','o','f','t','w','a','r','e','\\',
1329                                        'C','l','a','s','s','e','s','\\',
1330                                        'W','i','n','e',0};
1331     static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1332                                        'M','a','c','h','i','n','e','\\',
1333                                        'S','o','f','t','w','a','r','e','\\',
1334                                        'C','l','a','s','s','e','s','\\',
1335                                        'W','o','w','6','4','3','2','N','o','d','e','\\',
1336                                        'W','i','n','e',0};
1337     NTSTATUS status;
1338     OBJECT_ATTRIBUTES attr;
1339     UNICODE_STRING str;
1340     char buffer[1024];
1341     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1342     DWORD dw, len;
1343     HANDLE key, root32, root64, key32, key64;
1344     BOOL is_vista = FALSE;
1345 
1346     if (ptr_size != 64)
1347     {
1348         ULONG is_wow64, len;
1349         if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
1350                                         &is_wow64, sizeof(is_wow64), &len ) ||
1351             !is_wow64)
1352         {
1353             trace( "Not on Wow64, no redirection\n" );
1354             return;
1355         }
1356     }
1357 
1358     attr.Length = sizeof(attr);
1359     attr.RootDirectory = 0;
1360     attr.Attributes = OBJ_CASE_INSENSITIVE;
1361     attr.ObjectName = &str;
1362     attr.SecurityDescriptor = NULL;
1363     attr.SecurityQualityOfService = NULL;
1364 
1365     pRtlInitUnicodeString( &str, wine64W );
1366     status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1367     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1368 
1369     pRtlInitUnicodeString( &str, wine32W );
1370     status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1371     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1372 
1373     pRtlInitUnicodeString( &str, key64W );
1374     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1375     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1376 
1377     pRtlInitUnicodeString( &str, key32W );
1378     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1379     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1380 
1381     dw = 64;
1382     status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1383     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1384 
1385     dw = 32;
1386     status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1387     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1388 
1389     len = sizeof(buffer);
1390     status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1391     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1392     dw = *(DWORD *)info->Data;
1393     ok( dw == 32, "wrong value %u\n", dw );
1394 
1395     len = sizeof(buffer);
1396     status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1397     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1398     dw = *(DWORD *)info->Data;
1399     ok( dw == 64, "wrong value %u\n", dw );
1400 
1401     pRtlInitUnicodeString( &str, softwareW );
1402     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1403     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1404 
1405     if (ptr_size == 32)
1406     {
1407         /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1408         /* the new (and simpler) Win7 mechanism doesn't */
1409         if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1410         {
1411             trace( "using Vista-style Wow6432Node handling\n" );
1412             is_vista = TRUE;
1413         }
1414         check_key_value( key, "Wine\\Winetest", 0, 32 );
1415         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1416         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1417         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1418         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1419         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1420     }
1421     else
1422     {
1423         check_key_value( key, "Wine\\Winetest", 0, 64 );
1424         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1425     }
1426     pNtClose( key );
1427 
1428     if (ptr_size == 32)
1429     {
1430         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1431         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1432         dw = get_key_value( key, "Wine\\Winetest", 0 );
1433         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1434         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1435         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1436         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1437         dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1438         ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1439         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1440         pNtClose( key );
1441 
1442         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1443         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1444         check_key_value( key, "Wine\\Winetest", 0, 32 );
1445         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1446         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1447         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1448         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1449         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1450         pNtClose( key );
1451     }
1452 
1453     check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1454     check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1455     if (ptr_size == 64)
1456     {
1457         /* KEY_WOW64 flags have no effect on 64-bit */
1458         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1459         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1460         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1461         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1462     }
1463     else
1464     {
1465         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1466         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1467         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1468         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1469     }
1470 
1471     pRtlInitUnicodeString( &str, wownodeW );
1472     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1473     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1474     check_key_value( key, "Wine\\Winetest", 0, 32 );
1475     check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1476     check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1477     pNtClose( key );
1478 
1479     if (ptr_size == 32)
1480     {
1481         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1482         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1483         dw = get_key_value( key, "Wine\\Winetest", 0 );
1484         ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1485         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1486         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1487         pNtClose( key );
1488 
1489         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1490         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1491         check_key_value( key, "Wine\\Winetest", 0, 32 );
1492         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1493         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1494         pNtClose( key );
1495     }
1496 
1497     pRtlInitUnicodeString( &str, wine32W );
1498     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1499     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1500     check_key_value( key, "Winetest", 0, 32 );
1501     check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1502     check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1503     pNtClose( key );
1504 
1505     if (ptr_size == 32)
1506     {
1507         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1508         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1509         dw = get_key_value( key, "Winetest", 0 );
1510         ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1511         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1512         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1513         pNtClose( key );
1514 
1515         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1516         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1517         check_key_value( key, "Winetest", 0, 32 );
1518         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1519         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1520         pNtClose( key );
1521     }
1522 
1523     pRtlInitUnicodeString( &str, wine64W );
1524     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1525     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1526     check_key_value( key, "Winetest", 0, ptr_size );
1527     check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1528     check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1529     pNtClose( key );
1530 
1531     if (ptr_size == 32)
1532     {
1533         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1534         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1535         dw = get_key_value( key, "Winetest", 0 );
1536         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1537         check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1538         dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1539         todo_wine ok( dw == 32, "wrong value %u\n", dw );
1540         pNtClose( key );
1541 
1542         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1543         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1544         check_key_value( key, "Winetest", 0, 32 );
1545         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1546         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1547         pNtClose( key );
1548     }
1549 
1550     status = pNtDeleteKey( key32 );
1551     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1552     pNtClose( key32 );
1553 
1554     status = pNtDeleteKey( key64 );
1555     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1556     pNtClose( key64 );
1557 
1558     pNtDeleteKey( root32 );
1559     pNtClose( root32 );
1560     pNtDeleteKey( root64 );
1561     pNtClose( root64 );
1562 
1563     /* Software\Classes is shared/reflected so behavior is different */
1564 
1565     pRtlInitUnicodeString( &str, classes64W );
1566     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1567     if (status == STATUS_ACCESS_DENIED)
1568     {
1569         skip("Not authorized to modify the Classes key\n");
1570         return;
1571     }
1572     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1573 
1574     pRtlInitUnicodeString( &str, classes32W );
1575     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1576     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1577 
1578     dw = 64;
1579     status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1580     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1581     pNtClose( key64 );
1582 
1583     dw = 32;
1584     status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1585     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1586     pNtClose( key32 );
1587 
1588     pRtlInitUnicodeString( &str, classes64W );
1589     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1590     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1591     len = sizeof(buffer);
1592     status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1593     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1594     dw = *(DWORD *)info->Data;
1595     ok( dw == ptr_size, "wrong value %u\n", dw );
1596 
1597     pRtlInitUnicodeString( &str, classes32W );
1598     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1599     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1600     len = sizeof(buffer);
1601     status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1602     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1603     dw = *(DWORD *)info->Data;
1604     ok( dw == 32, "wrong value %u\n", dw );
1605 
1606     pNtDeleteKey( key32 );
1607     pNtClose( key32 );
1608     pNtDeleteKey( key64 );
1609     pNtClose( key64 );
1610 }
1611 
1612 static void test_long_value_name(void)
1613 {
1614     HANDLE key;
1615     NTSTATUS status, expected;
1616     OBJECT_ATTRIBUTES attr;
1617     UNICODE_STRING ValName;
1618     DWORD i;
1619 
1620     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1621     status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1622     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1623 
1624     ValName.MaximumLength = 0xfffc;
1625     ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1626     ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1627     for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1628         ValName.Buffer[i] = 'a';
1629     ValName.Buffer[i] = 0;
1630 
1631     status = pNtDeleteValueKey(key, &ValName);
1632     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1633     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1634     ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1635        "NtSetValueKey with long value name returned 0x%08x\n", status);
1636     expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1637     status = pNtDeleteValueKey(key, &ValName);
1638     ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1639 
1640     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1641     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1642 
1643     pRtlFreeUnicodeString(&ValName);
1644     pNtClose(key);
1645 }
1646 
1647 static void test_NtQueryKey(void)
1648 {
1649     HANDLE key, subkey, subkey2;
1650     NTSTATUS status;
1651     OBJECT_ATTRIBUTES attr;
1652     ULONG length, len;
1653     KEY_NAME_INFORMATION *info = NULL;
1654     KEY_CACHED_INFORMATION cached_info;
1655     UNICODE_STRING str;
1656     DWORD dw;
1657 
1658     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1659     status = pNtOpenKey(&key, KEY_READ, &attr);
1660     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1661 
1662     status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
1663     if (status == STATUS_INVALID_PARAMETER) {
1664         win_skip("KeyNameInformation is not supported\n");
1665         pNtClose(key);
1666         return;
1667     }
1668     todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1669     info = HeapAlloc(GetProcessHeap(), 0, length);
1670 
1671     /* non-zero buffer size, but insufficient */
1672     status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
1673     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
1674     ok(length == len, "got %d, expected %d\n", len, length);
1675     ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
1676        info->NameLength, winetestpath.Length);
1677 
1678     /* correct buffer size */
1679     status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
1680     ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1681     ok(length == len, "got %d, expected %d\n", len, length);
1682 
1683     str.Buffer = info->Name;
1684     str.Length = info->NameLength;
1685     ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1686        "got %s, expected %s\n",
1687        wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1688        wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1689 
1690     HeapFree(GetProcessHeap(), 0, info);
1691 
1692     attr.RootDirectory = key;
1693     attr.ObjectName = &str;
1694     pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1695     status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1696     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1697     pRtlFreeUnicodeString(&str);
1698 
1699     status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1700     ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1701 
1702     if (status == STATUS_SUCCESS)
1703     {
1704         ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1705         ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1706         ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1707         ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
1708         ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1709         ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1710         ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1711     }
1712 
1713     attr.RootDirectory = subkey;
1714     attr.ObjectName = &str;
1715     pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
1716     status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
1717     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1718     pRtlFreeUnicodeString(&str);
1719 
1720     pRtlCreateUnicodeStringFromAsciiz(&str, "val");
1721     dw = 64;
1722     status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
1723     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1724     pRtlFreeUnicodeString(&str);
1725 
1726     if (!winetest_interactive)
1727         skip("ROSTESTS-198: Causes an assert in Cm.\n");
1728     else
1729     {
1730         status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1731         ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1732 
1733         if (status == STATUS_SUCCESS)
1734         {
1735             ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1736             ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1737             ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1738             ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
1739             ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1740             ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1741             ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1742         }
1743     }
1744 
1745     status = pNtDeleteKey(subkey2);
1746     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1747     status = pNtDeleteKey(subkey);
1748     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1749 
1750     pNtClose(subkey2);
1751     pNtClose(subkey);
1752     pNtClose(key);
1753 }
1754 
1755 static void test_notify(void)
1756 {
1757     OBJECT_ATTRIBUTES attr;
1758     LARGE_INTEGER timeout;
1759     IO_STATUS_BLOCK iosb;
1760     UNICODE_STRING str;
1761     HANDLE key, events[2], subkey;
1762     NTSTATUS status;
1763 
1764     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1765     status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1766     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1767 
1768     events[0] = CreateEventW(NULL, FALSE, TRUE, NULL);
1769     ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError());
1770     events[1] = CreateEventW(NULL, FALSE, TRUE, NULL);
1771     ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError());
1772 
1773     status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1774     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1775     status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1776     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1777 
1778     timeout.QuadPart = 0;
1779     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1780     ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1781     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1782     ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1783 
1784     attr.RootDirectory = key;
1785     attr.ObjectName = &str;
1786 
1787     pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1788     status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1789     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1790     pRtlFreeUnicodeString(&str);
1791 
1792     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1793     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1794     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1795     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1796 
1797     status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1798     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1799     status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1800     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1801 
1802     status = pNtDeleteKey(subkey);
1803     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1804 
1805     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1806     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1807     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1808     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1809 
1810     pNtClose(subkey);
1811 
1812     status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1813     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1814     status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1815     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1816 
1817     pNtClose(key);
1818 
1819     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1820     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1821     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1822     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1823 
1824     if (pNtNotifyChangeMultipleKeys)
1825     {
1826         InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1827         status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1828         ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1829 
1830         status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1831         ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1832 
1833         timeout.QuadPart = 0;
1834         status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1835         ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1836 
1837         attr.RootDirectory = key;
1838         attr.ObjectName = &str;
1839         pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1840         status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1841         ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1842         pRtlFreeUnicodeString(&str);
1843 
1844         status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1845         ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1846 
1847         status = pNtDeleteKey(subkey);
1848         ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1849         pNtClose(subkey);
1850         pNtClose(key);
1851     }
1852     else
1853     {
1854         win_skip("NtNotifyChangeMultipleKeys not available\n");
1855     }
1856 
1857     pNtClose(events[0]);
1858     pNtClose(events[1]);
1859 }
1860 
1861 START_TEST(reg)
1862 {
1863     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1864     if(!InitFunctionPtrs())
1865         return;
1866     pRtlFormatCurrentUserKeyPath(&winetestpath);
1867     winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1868                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1869     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1870 
1871     pRtlAppendUnicodeToString(&winetestpath, winetest);
1872 
1873     test_NtCreateKey();
1874     test_NtOpenKey();
1875     test_NtSetValueKey();
1876     test_RtlCheckRegistryKey();
1877     test_RtlOpenCurrentUser();
1878     test_RtlQueryRegistryValues();
1879     test_RtlpNtQueryValueKey();
1880     test_NtFlushKey();
1881     test_NtQueryKey();
1882     test_NtQueryLicenseKey();
1883     test_NtQueryValueKey();
1884     test_long_value_name();
1885     test_notify();
1886     test_NtDeleteKey();
1887     test_symlinks();
1888     test_redirection();
1889 
1890     pRtlFreeUnicodeString(&winetestpath);
1891 
1892     FreeLibrary(hntdll);
1893 }
1894