xref: /reactos/modules/rostests/winetests/ntdll/reg.c (revision 40462c92)
1 /* Unit test suite for Rtl* Registry API functions
2  *
3  * Copyright 2003 Thomas Mertes
4  * Copyright 2005 Brad DeMorrow
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through
21  * helper function RTL_GetKeyHandle().--Brad DeMorrow
22  *
23  */
24 
25 #include "ntdll_test.h"
26 #include "winternl.h"
27 #include "stdio.h"
28 #include "winnt.h"
29 #include "winnls.h"
30 #include "stdlib.h"
31 
32 /* A test string */
33 static const WCHAR stringW[] = {'s', 't', 'r', 'i', 'n', 'g', 'W', 0};
34 /* A size, in bytes, short enough to cause truncation of the above */
35 #define STR_TRUNC_SIZE (sizeof(stringW)-2*sizeof(*stringW))
36 
37 #ifndef __WINE_WINTERNL_H
38 
39 /* RtlQueryRegistryValues structs and defines */
40 #define RTL_REGISTRY_ABSOLUTE             0
41 #define RTL_REGISTRY_SERVICES             1
42 #define RTL_REGISTRY_CONTROL              2
43 #define RTL_REGISTRY_WINDOWS_NT           3
44 #define RTL_REGISTRY_DEVICEMAP            4
45 #define RTL_REGISTRY_USER                 5
46 
47 #define RTL_REGISTRY_HANDLE       0x40000000
48 #define RTL_REGISTRY_OPTIONAL     0x80000000
49 
50 #define RTL_QUERY_REGISTRY_SUBKEY         0x00000001
51 #define RTL_QUERY_REGISTRY_TOPKEY         0x00000002
52 #define RTL_QUERY_REGISTRY_REQUIRED       0x00000004
53 #define RTL_QUERY_REGISTRY_NOVALUE        0x00000008
54 #define RTL_QUERY_REGISTRY_NOEXPAND       0x00000010
55 #define RTL_QUERY_REGISTRY_DIRECT         0x00000020
56 #define RTL_QUERY_REGISTRY_DELETE         0x00000040
57 
58 typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR  ValueName,
59                                                         ULONG  ValueType,
60                                                         PVOID  ValueData,
61                                                         ULONG  ValueLength,
62                                                         PVOID  Context,
63                                                         PVOID  EntryContext);
64 
65 typedef struct _RTL_QUERY_REGISTRY_TABLE {
66   PRTL_QUERY_REGISTRY_ROUTINE  QueryRoutine;
67   ULONG  Flags;
68   PWSTR  Name;
69   PVOID  EntryContext;
70   ULONG  DefaultType;
71   PVOID  DefaultData;
72   ULONG  DefaultLength;
73 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
74 
75 typedef struct _KEY_VALUE_BASIC_INFORMATION {
76     ULONG TitleIndex;
77     ULONG Type;
78     ULONG NameLength;
79     WCHAR Name[1];
80 } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
81 
82 typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
83     ULONG TitleIndex;
84     ULONG Type;
85     ULONG DataLength;
86     UCHAR Data[1];
87 } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
88 
89 typedef struct _KEY_VALUE_FULL_INFORMATION {
90     ULONG TitleIndex;
91     ULONG Type;
92     ULONG DataOffset;
93     ULONG DataLength;
94     ULONG NameLength;
95     WCHAR Name[1];
96 } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
97 
98 typedef enum _KEY_VALUE_INFORMATION_CLASS {
99     KeyValueBasicInformation,
100     KeyValueFullInformation,
101     KeyValuePartialInformation,
102     KeyValueFullInformationAlign64,
103     KeyValuePartialInformationAlign64
104 } KEY_VALUE_INFORMATION_CLASS;
105 
106 #define InitializeObjectAttributes(p,n,a,r,s) \
107     do { \
108         (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
109         (p)->RootDirectory = r; \
110         (p)->Attributes = a; \
111         (p)->ObjectName = n; \
112         (p)->SecurityDescriptor = s; \
113         (p)->SecurityQualityOfService = NULL; \
114     } while (0)
115 
116 #endif
117 
118 static 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     key = (HANDLE)0xdeadbeef;
368     status = pNtOpenKey(&key, 0, &attr);
369 todo_wine
370     ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
371 todo_wine
372     ok(!key, "key = %p\n", key);
373     if (status == STATUS_SUCCESS) NtClose(key);
374 
375     /* Calling without parent key requres full registry path. */
376     pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
377     InitializeObjectAttributes(&attr, &str, 0, 0, 0);
378     key = (HANDLE)0xdeadbeef;
379     status = pNtOpenKey(&key, KEY_READ, &attr);
380     todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
381 todo_wine
382     ok(!key, "key = %p\n", key);
383     pRtlFreeUnicodeString( &str );
384 
385     /* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
386     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine" );
387     status = pNtOpenKey(&key, KEY_READ, &attr);
388     todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey Failed: 0x%08x\n", status);
389 
390     attr.Attributes = OBJ_CASE_INSENSITIVE;
391     status = pNtOpenKey(&key, KEY_READ, &attr);
392     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
393     pNtClose(key);
394     pRtlFreeUnicodeString( &str );
395 
396     pRtlCreateUnicodeStringFromAsciiz( &str, "" );
397     status = pNtOpenKey(&key, KEY_READ, &attr);
398     todo_wine
399     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
400     pRtlFreeUnicodeString( &str );
401 
402     pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
403     status = pNtOpenKey(&key, KEY_READ, &attr);
404     todo_wine
405     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
406     pRtlFreeUnicodeString( &str );
407 
408     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
409     status = pNtOpenKey(&key, KEY_READ, &attr);
410     todo_wine
411     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
412     pNtClose( key );
413     pRtlFreeUnicodeString( &str );
414 
415     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
416     status = pNtOpenKey(&key, KEY_READ, &attr);
417     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
418     pNtClose( key );
419     pRtlFreeUnicodeString( &str );
420 
421     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
422     status = pNtOpenKey(&key, KEY_READ, &attr);
423     todo_wine
424     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
425     pRtlFreeUnicodeString( &str );
426 
427     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
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_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
437     pRtlFreeUnicodeString( &str );
438 
439     pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
440     status = pNtOpenKey(&key, KEY_READ, &attr);
441     todo_wine
442     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
443     pRtlFreeUnicodeString( &str );
444 
445     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
446     status = pNtOpenKey(&key, KEY_READ, &attr);
447     todo_wine
448     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
449     pRtlFreeUnicodeString( &str );
450 
451     if (!pNtOpenKeyEx)
452     {
453         win_skip("NtOpenKeyEx not available\n");
454         return;
455     }
456 
457     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
458     status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0);
459     ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status);
460 
461     pNtClose(key);
462 }
463 
464 static void test_NtCreateKey(void)
465 {
466     /*Create WineTest*/
467     OBJECT_ATTRIBUTES attr;
468     HANDLE key, subkey;
469     ACCESS_MASK am = GENERIC_ALL;
470     NTSTATUS status;
471     UNICODE_STRING str;
472 
473     /* All NULL */
474     status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
475     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
476        "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
477 
478     /* Only the key */
479     status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
480     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
481         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
482 
483     /* Only accessmask */
484     status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
485     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
486        "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
487 
488     /* Key and accessmask */
489     status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
490     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
491         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
492 
493     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
494 
495     /* Only attributes */
496     status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
497     ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
498        "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
499 
500     /* Length > sizeof(OBJECT_ATTRIBUTES) */
501     attr.Length *= 2;
502     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
503     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
504 
505     attr.Length = sizeof(attr);
506     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
507     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
508 
509     attr.RootDirectory = key;
510     attr.ObjectName = &str;
511 
512     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
513     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
514     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
515     pRtlFreeUnicodeString( &str );
516 
517     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
518     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
519     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
520     pRtlFreeUnicodeString( &str );
521 
522     pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
523     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
524     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
525     pRtlFreeUnicodeString( &str );
526 
527     pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
528     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
529     ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
530         "NtCreateKey failed: 0x%08x\n", status );
531     if (status == STATUS_SUCCESS)
532     {
533         pNtDeleteKey( subkey );
534         pNtClose( subkey );
535     }
536     pRtlFreeUnicodeString( &str );
537 
538     pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
539     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
540     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
541     pRtlFreeUnicodeString( &str );
542     pNtDeleteKey( subkey );
543     pNtClose( subkey );
544 
545     attr.RootDirectory = 0;
546     attr.Attributes = OBJ_CASE_INSENSITIVE;
547 
548     pRtlCreateUnicodeStringFromAsciiz( &str, "" );
549     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
550     todo_wine
551     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
552     pRtlFreeUnicodeString( &str );
553 
554     pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
555     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
556     todo_wine
557     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
558     pRtlFreeUnicodeString( &str );
559 
560     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
561     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
562     todo_wine
563     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
564         "NtCreateKey failed: 0x%08x\n", status );
565     if (!status) pNtClose( subkey );
566     pRtlFreeUnicodeString( &str );
567 
568     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
569     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
570     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
571         "NtCreateKey failed: 0x%08x\n", status );
572     if (!status) pNtClose( subkey );
573     pRtlFreeUnicodeString( &str );
574 
575     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
576     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
577     todo_wine
578     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
579     pRtlFreeUnicodeString( &str );
580 
581     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
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_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
591     pRtlFreeUnicodeString( &str );
592 
593     pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
594     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
595     todo_wine
596     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
597     pRtlFreeUnicodeString( &str );
598 
599     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
600     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
601     todo_wine
602     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
603     pRtlFreeUnicodeString( &str );
604 
605     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
606     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
607     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
608         "NtCreateKey failed: 0x%08x\n", status );
609     if (!status) pNtClose( subkey );
610     pRtlFreeUnicodeString( &str );
611 
612     /* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */
613     attr.Attributes = 0;
614     pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
615     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
616     todo_wine
617     ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
618     pRtlFreeUnicodeString( &str );
619 
620     pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\Machine\\Software\\Classes" );
621     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
622     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
623         "NtCreateKey failed: 0x%08x\n", status );
624     if (!status) pNtClose( subkey );
625     pRtlFreeUnicodeString( &str );
626 
627     pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" );
628     status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
629     ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
630         "NtCreateKey failed: 0x%08x\n", status );
631     if (!status) pNtClose( subkey );
632     pRtlFreeUnicodeString( &str );
633 
634     pNtClose(key);
635 }
636 
637 static void test_NtSetValueKey(void)
638 {
639     HANDLE key;
640     NTSTATUS status;
641     OBJECT_ATTRIBUTES attr;
642     ACCESS_MASK am = KEY_WRITE;
643     UNICODE_STRING ValName;
644     DWORD data = 711;
645 
646     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
647     status = pNtOpenKey(&key, am, &attr);
648     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
649 
650     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
651     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
652     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
653     pRtlFreeUnicodeString(&ValName);
654 
655     pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
656     status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
657     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
658     pRtlFreeUnicodeString(&ValName);
659 
660     pNtClose(key);
661 }
662 
663 static void test_RtlOpenCurrentUser(void)
664 {
665     NTSTATUS status;
666     HANDLE handle;
667     status=pRtlOpenCurrentUser(KEY_READ, &handle);
668     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
669     pNtClose(handle);
670 }
671 
672 static void test_RtlCheckRegistryKey(void)
673 {
674     NTSTATUS status;
675 
676     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
677     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
678 
679     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
680     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
681 }
682 
683 static void test_NtFlushKey(void)
684 {
685     NTSTATUS status;
686     HANDLE hkey;
687     OBJECT_ATTRIBUTES attr;
688     ACCESS_MASK am = KEY_ALL_ACCESS;
689 
690     status = pNtFlushKey(NULL);
691     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
692 
693     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
694     pNtOpenKey(&hkey, am, &attr);
695 
696     status = pNtFlushKey(hkey);
697     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
698 
699     pNtClose(hkey);
700 }
701 
702 static void test_NtQueryValueKey(void)
703 {
704     HANDLE key;
705     NTSTATUS status;
706     OBJECT_ATTRIBUTES attr;
707     UNICODE_STRING ValName;
708     KEY_VALUE_BASIC_INFORMATION *basic_info;
709     KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi;
710     KEY_VALUE_FULL_INFORMATION *full_info;
711     DWORD len, expected;
712 
713     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
714 
715     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
716     status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr);
717     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
718 
719     len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
720     basic_info = HeapAlloc(GetProcessHeap(), 0, len);
721     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
722     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
723     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
724     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
725     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
726     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
727 
728     basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
729     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
730     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
731     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
732     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
733     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
734     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
735     ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
736     HeapFree(GetProcessHeap(), 0, basic_info);
737 
738     len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
739     partial_info = HeapAlloc(GetProcessHeap(), 0, len);
740     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
741     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
742     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
743     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
744     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
745     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
746 
747     partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
748     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
749     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
750     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
751     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
752     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
753     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
754     ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
755     HeapFree(GetProcessHeap(), 0, partial_info);
756 
757     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
758     full_info = HeapAlloc(GetProcessHeap(), 0, len);
759     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
760     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
761     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
762     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
763     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
764     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
765     ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
766         "NtQueryValueKey returned wrong len %d\n", len);
767     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
768 
769     full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
770     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
771     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
772     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
773     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
774     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
775     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
776     ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
777     ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
778         *(DWORD *)((char *)full_info + full_info->DataOffset));
779     HeapFree(GetProcessHeap(), 0, full_info);
780 
781     pRtlFreeUnicodeString(&ValName);
782     pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
783 
784     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
785     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
786     partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
787     memset(partial_info, 0xbd, len+1);
788     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
789     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
790     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
791     ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
792     ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
793     ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
794     ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
795 
796     expected = len;
797     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &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, 1, &len);
801     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
802     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
803     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
804     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
805     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
806     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
807     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
808     ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
809 
810     HeapFree(GetProcessHeap(), 0, partial_info);
811     pRtlFreeUnicodeString(&ValName);
812 
813     pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest");
814     status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0);
815     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
816 
817     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
818     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
819     ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type);
820     ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength);
821     pRtlFreeUnicodeString(&ValName);
822 
823     pNtClose(key);
824 }
825 
826 static void test_NtDeleteKey(void)
827 {
828     NTSTATUS status;
829     HANDLE hkey;
830     OBJECT_ATTRIBUTES attr;
831     ACCESS_MASK am = KEY_ALL_ACCESS;
832 
833     status = pNtDeleteKey(NULL);
834     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
835 
836     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
837     status = pNtOpenKey(&hkey, am, &attr);
838     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
839 
840     status = pNtDeleteKey(hkey);
841     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
842 }
843 
844 static void test_NtQueryLicenseKey(void)
845 {
846     static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
847     UNICODE_STRING name;
848     WORD buffer[32];
849     NTSTATUS status;
850     ULONG type, len;
851     DWORD value;
852 
853     if (!pNtQueryLicenseValue)
854     {
855         win_skip("NtQueryLicenseValue not found, skipping tests\n");
856         return;
857     }
858 
859     type = 0xdead;
860     len = 0xbeef;
861     memset(&name, 0, sizeof(name));
862     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
863     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
864     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
865     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
866 
867     /* test with empty key */
868     pRtlCreateUnicodeStringFromAsciiz(&name, "");
869 
870     type = 0xdead;
871     len = 0xbeef;
872     status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
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     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
876 
877     type = 0xdead;
878     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
879     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
880     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
881 
882     len = 0xbeef;
883     status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
884     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
885     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
886 
887     type = 0xdead;
888     len = 0xbeef;
889     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
890     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
891     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
892     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
893 
894     pRtlFreeUnicodeString(&name);
895 
896     /* test with nonexistent licence key */
897     pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
898 
899     type = 0xdead;
900     len = 0xbeef;
901     status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
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     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
905 
906     type = 0xdead;
907     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
908     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
909     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
910 
911     len = 0xbeef;
912     status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
913     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
914     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
915 
916     type = 0xdead;
917     len = 0xbeef;
918     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
919     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n");
920     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
921     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
922 
923     pRtlFreeUnicodeString(&name);
924 
925     /* test with REG_SZ license key */
926     pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
927 
928     type = 0xdead;
929     len = 0xbeef;
930     status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
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     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
934 
935     type = 0xdead;
936     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
937     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
938     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
939 
940     type = 0xdead;
941     len = 0;
942     status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
943     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
944     ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
945     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
946 
947     len = 0;
948     status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
949     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
950     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
951 
952     type = 0xdead;
953     len = 0;
954     memset(buffer, 0x11, sizeof(buffer));
955     status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
956     ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
957     ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
958     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
959     ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
960 
961     type = 0xdead;
962     len = 0;
963     memset(buffer, 0x11, sizeof(buffer));
964     status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
965     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
966     ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
967     ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
968     ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
969 
970     pRtlFreeUnicodeString(&name);
971 
972     /* test with REG_DWORD license key */
973     pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
974 
975     type = 0xdead;
976     len = 0xbeef;
977     status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
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     ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
981 
982     type = 0xdead;
983     status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
984     ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
985     ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
986 
987     type = 0xdead;
988     len = 0;
989     status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
990     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
991     ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
992     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
993 
994     len = 0;
995     status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
996     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
997     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
998 
999     type = 0xdead;
1000     len = 0;
1001     value = 0xdeadbeef;
1002     status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
1003     ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
1004     ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
1005     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1006     ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
1007 
1008     type = 0xdead;
1009     len = 0;
1010     status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
1011     ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
1012     ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
1013     ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1014 
1015     pRtlFreeUnicodeString(&name);
1016 }
1017 
1018 static void test_RtlpNtQueryValueKey(void)
1019 {
1020     NTSTATUS status;
1021 
1022     status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
1023     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
1024 }
1025 
1026 static void test_symlinks(void)
1027 {
1028     static const WCHAR linkW[] = {'l','i','n','k',0};
1029     static const WCHAR valueW[] = {'v','a','l','u','e',0};
1030     static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
1031     static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
1032     static UNICODE_STRING null_str;
1033     char buffer[1024];
1034     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1035     WCHAR *target;
1036     UNICODE_STRING symlink_str, link_str, target_str, value_str;
1037     HANDLE root, key, link;
1038     OBJECT_ATTRIBUTES attr;
1039     NTSTATUS status;
1040     DWORD target_len, len, dw;
1041 
1042     pRtlInitUnicodeString( &link_str, linkW );
1043     pRtlInitUnicodeString( &symlink_str, symlinkW );
1044     pRtlInitUnicodeString( &target_str, targetW + 1 );
1045     pRtlInitUnicodeString( &value_str, valueW );
1046 
1047     target_len = winetestpath.Length + sizeof(targetW);
1048     target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
1049     memcpy( target, winetestpath.Buffer, winetestpath.Length );
1050     memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
1051 
1052     attr.Length = sizeof(attr);
1053     attr.RootDirectory = 0;
1054     attr.Attributes = 0;
1055     attr.ObjectName = &winetestpath;
1056     attr.SecurityDescriptor = NULL;
1057     attr.SecurityQualityOfService = NULL;
1058 
1059     status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1060     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1061 
1062     attr.RootDirectory = root;
1063     attr.ObjectName = &link_str;
1064     status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1065     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1066 
1067     /* REG_SZ is not allowed */
1068     status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
1069     ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1070     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1071     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1072     /* other values are not allowed */
1073     status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1074     ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1075 
1076     /* try opening the target through the link */
1077 
1078     attr.ObjectName = &link_str;
1079     key = (HANDLE)0xdeadbeef;
1080     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1081     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1082     ok( !key, "key = %p\n", key );
1083 
1084     attr.ObjectName = &target_str;
1085     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1086     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1087 
1088     dw = 0xbeef;
1089     status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1090     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1091     pNtClose( key );
1092 
1093     attr.ObjectName = &link_str;
1094     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1095     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1096 
1097     len = sizeof(buffer);
1098     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1099     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1100     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1101 
1102     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1103     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1104 
1105     /* REG_LINK can be created in non-link keys */
1106     status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1107     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1108     len = sizeof(buffer);
1109     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1110     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1111     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1112         "wrong len %u\n", len );
1113     status = pNtDeleteValueKey( key, &symlink_str );
1114     ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
1115 
1116     pNtClose( key );
1117 
1118     attr.Attributes = 0;
1119     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1120     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1121 
1122     len = sizeof(buffer);
1123     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1124     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1125     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1126 
1127     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1128     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1129     pNtClose( key );
1130 
1131     /* now open the symlink itself */
1132 
1133     attr.RootDirectory = root;
1134     attr.Attributes = OBJ_OPENLINK;
1135     attr.ObjectName = &link_str;
1136     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1137     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1138 
1139     len = sizeof(buffer);
1140     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1141     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1142     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1143         "wrong len %u\n", len );
1144     pNtClose( key );
1145 
1146     if (pNtOpenKeyEx)
1147     {
1148         /* REG_OPTION_OPEN_LINK flag doesn't matter */
1149         status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
1150         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1151 
1152         len = sizeof(buffer);
1153         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1154         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1155         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1156             "wrong len %u\n", len );
1157         pNtClose( key );
1158 
1159         status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 );
1160         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1161 
1162         len = sizeof(buffer);
1163         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1164         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1165         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1166             "wrong len %u\n", len );
1167         pNtClose( key );
1168 
1169         attr.Attributes = 0;
1170         status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
1171         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1172 
1173         len = sizeof(buffer);
1174         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1175         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1176         pNtClose( key );
1177     }
1178 
1179     attr.Attributes = OBJ_OPENLINK;
1180     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1181     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1182     len = sizeof(buffer);
1183     status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1184     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1185     ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1186         "wrong len %u\n", len );
1187     pNtClose( key );
1188 
1189     /* delete target and create by NtCreateKey on link */
1190     attr.ObjectName = &target_str;
1191     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1192     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1193     status = pNtDeleteKey( key );
1194     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1195     pNtClose( key );
1196 
1197     attr.ObjectName = &link_str;
1198     attr.Attributes = 0;
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     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1203     todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1204     pNtClose( key );
1205     if (status) /* can be removed once todo_wine above is fixed */
1206     {
1207         attr.ObjectName = &target_str;
1208         attr.Attributes = OBJ_OPENLINK;
1209         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1210         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1211         pNtClose( key );
1212     }
1213 
1214     attr.ObjectName = &target_str;
1215     attr.Attributes = OBJ_OPENLINK;
1216     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1217     ok( status == STATUS_SUCCESS, "NtOpenKey wrong status 0x%08x\n", status );
1218 
1219     if (0)  /* crashes the Windows kernel on some Vista systems */
1220     {
1221         /* reopen the link from itself */
1222 
1223         attr.RootDirectory = link;
1224         attr.Attributes = OBJ_OPENLINK;
1225         attr.ObjectName = &null_str;
1226         status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1227         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1228         len = sizeof(buffer);
1229         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1230         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1231         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1232             "wrong len %u\n", len );
1233         pNtClose( key );
1234 
1235         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1236         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1237         len = sizeof(buffer);
1238         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1239         ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1240         ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1241             "wrong len %u\n", len );
1242         pNtClose( key );
1243     }
1244 
1245     if (0)  /* crashes the Windows kernel in most versions */
1246     {
1247         attr.RootDirectory = link;
1248         attr.Attributes = 0;
1249         attr.ObjectName = &null_str;
1250         status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1251         ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1252         len = sizeof(buffer);
1253         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1254         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1255         pNtClose( key );
1256 
1257         status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1258         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1259         len = sizeof(buffer);
1260         status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1261         ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1262         pNtClose( key );
1263     }
1264 
1265     /* target with terminating null doesn't work */
1266     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
1267     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1268     attr.RootDirectory = root;
1269     attr.Attributes = 0;
1270     attr.ObjectName = &link_str;
1271     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1272     ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1273 
1274     /* relative symlink, works only on win2k */
1275     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
1276     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1277     attr.ObjectName = &link_str;
1278     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1279     ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
1280         "NtOpenKey wrong status 0x%08x\n", status );
1281 
1282     key = (HKEY)0xdeadbeef;
1283     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, NULL );
1284     ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
1285     ok( !key, "key = %p\n", key );
1286 
1287     status = pNtDeleteKey( link );
1288     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1289     pNtClose( link );
1290 
1291     attr.ObjectName = &target_str;
1292     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1293     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1294     status = pNtDeleteKey( key );
1295     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1296     pNtClose( key );
1297 
1298     /* symlink loop */
1299 
1300     status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1301     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1302     memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
1303     status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
1304         target, target_len + sizeof(targetW) - sizeof(WCHAR) );
1305     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1306 
1307     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1308     ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
1309         "NtOpenKey failed: 0x%08x\n", status );
1310 
1311     attr.Attributes = OBJ_OPENLINK;
1312     status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1313     ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1314     pNtClose( key );
1315 
1316     status = pNtDeleteKey( link );
1317     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1318     pNtClose( link );
1319 
1320     status = pNtDeleteKey( root );
1321     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1322     pNtClose( root );
1323 
1324     pRtlFreeHeap(GetProcessHeap(), 0, target);
1325 }
1326 
1327 static WCHAR valueW[] = {'v','a','l','u','e'};
1328 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
1329 static const DWORD ptr_size = 8 * sizeof(void*);
1330 
1331 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
1332 {
1333     char tmp[32];
1334     NTSTATUS status;
1335     OBJECT_ATTRIBUTES attr;
1336     UNICODE_STRING str;
1337     HANDLE key;
1338     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
1339     DWORD dw, len = sizeof(tmp);
1340 
1341     attr.Length = sizeof(attr);
1342     attr.RootDirectory = root;
1343     attr.Attributes = OBJ_CASE_INSENSITIVE;
1344     attr.ObjectName = &str;
1345     attr.SecurityDescriptor = NULL;
1346     attr.SecurityQualityOfService = NULL;
1347     pRtlCreateUnicodeStringFromAsciiz( &str, name );
1348 
1349     status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1350     if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
1351     ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
1352 
1353     status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1354     if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1355         dw = 0;
1356     else
1357     {
1358         ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
1359         dw = *(DWORD *)info->Data;
1360     }
1361     pNtClose( key );
1362     pRtlFreeUnicodeString( &str );
1363     return dw;
1364 }
1365 
1366 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
1367 {
1368     DWORD dw = get_key_value( root, name, flags );
1369     ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
1370 }
1371 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
1372 
1373 static void test_redirection(void)
1374 {
1375     static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1376                                       'M','a','c','h','i','n','e','\\',
1377                                       'S','o','f','t','w','a','r','e',0};
1378     static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1379                                      'M','a','c','h','i','n','e','\\',
1380                                      'S','o','f','t','w','a','r','e','\\',
1381                                      'W','o','w','6','4','3','2','N','o','d','e',0};
1382     static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1383                                     'M','a','c','h','i','n','e','\\',
1384                                     'S','o','f','t','w','a','r','e','\\',
1385                                     'W','i','n','e',0};
1386     static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1387                                     'M','a','c','h','i','n','e','\\',
1388                                     'S','o','f','t','w','a','r','e','\\',
1389                                     'W','o','w','6','4','3','2','N','o','d','e','\\',
1390                                     'W','i','n','e',0};
1391     static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1392                                    'M','a','c','h','i','n','e','\\',
1393                                    'S','o','f','t','w','a','r','e','\\',
1394                                    'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
1395     static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1396                                    'M','a','c','h','i','n','e','\\',
1397                                    'S','o','f','t','w','a','r','e','\\',
1398                                    'W','o','w','6','4','3','2','N','o','d','e','\\',
1399                                    'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
1400     static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1401                                        'M','a','c','h','i','n','e','\\',
1402                                        'S','o','f','t','w','a','r','e','\\',
1403                                        'C','l','a','s','s','e','s','\\',
1404                                        'W','i','n','e',0};
1405     static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1406                                        'M','a','c','h','i','n','e','\\',
1407                                        'S','o','f','t','w','a','r','e','\\',
1408                                        'C','l','a','s','s','e','s','\\',
1409                                        'W','o','w','6','4','3','2','N','o','d','e','\\',
1410                                        'W','i','n','e',0};
1411     NTSTATUS status;
1412     OBJECT_ATTRIBUTES attr;
1413     UNICODE_STRING str;
1414     char buffer[1024];
1415     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1416     DWORD dw, len;
1417     HANDLE key, root32, root64, key32, key64;
1418     BOOL is_vista = FALSE;
1419 
1420     if (ptr_size != 64)
1421     {
1422         ULONG is_wow64, len;
1423         if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
1424                                         &is_wow64, sizeof(is_wow64), &len ) ||
1425             !is_wow64)
1426         {
1427             trace( "Not on Wow64, no redirection\n" );
1428             return;
1429         }
1430     }
1431 
1432     attr.Length = sizeof(attr);
1433     attr.RootDirectory = 0;
1434     attr.Attributes = OBJ_CASE_INSENSITIVE;
1435     attr.ObjectName = &str;
1436     attr.SecurityDescriptor = NULL;
1437     attr.SecurityQualityOfService = NULL;
1438 
1439     pRtlInitUnicodeString( &str, wine64W );
1440     status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1441     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1442 
1443     pRtlInitUnicodeString( &str, wine32W );
1444     status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1445     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1446 
1447     pRtlInitUnicodeString( &str, key64W );
1448     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1449     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1450 
1451     pRtlInitUnicodeString( &str, key32W );
1452     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1453     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1454 
1455     dw = 64;
1456     status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1457     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1458 
1459     dw = 32;
1460     status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1461     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1462 
1463     len = sizeof(buffer);
1464     status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1465     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1466     dw = *(DWORD *)info->Data;
1467     ok( dw == 32, "wrong value %u\n", dw );
1468 
1469     len = sizeof(buffer);
1470     status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1471     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1472     dw = *(DWORD *)info->Data;
1473     ok( dw == 64, "wrong value %u\n", dw );
1474 
1475     pRtlInitUnicodeString( &str, softwareW );
1476     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1477     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1478 
1479     if (ptr_size == 32)
1480     {
1481         /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1482         /* the new (and simpler) Win7 mechanism doesn't */
1483         if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1484         {
1485             trace( "using Vista-style Wow6432Node handling\n" );
1486             is_vista = TRUE;
1487         }
1488         check_key_value( key, "Wine\\Winetest", 0, 32 );
1489         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1490         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1491         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1492         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1493         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1494     }
1495     else
1496     {
1497         check_key_value( key, "Wine\\Winetest", 0, 64 );
1498         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1499     }
1500     pNtClose( key );
1501 
1502     if (ptr_size == 32)
1503     {
1504         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1505         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1506         dw = get_key_value( key, "Wine\\Winetest", 0 );
1507         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1508         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1509         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1510         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1511         dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1512         ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1513         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1514         pNtClose( key );
1515 
1516         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1517         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1518         check_key_value( key, "Wine\\Winetest", 0, 32 );
1519         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1520         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1521         check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1522         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1523         check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1524         pNtClose( key );
1525     }
1526 
1527     check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1528     check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1529     if (ptr_size == 64)
1530     {
1531         /* KEY_WOW64 flags have no effect on 64-bit */
1532         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1533         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1534         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1535         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1536     }
1537     else
1538     {
1539         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1540         check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1541         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1542         check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1543     }
1544 
1545     pRtlInitUnicodeString( &str, wownodeW );
1546     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1547     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1548     check_key_value( key, "Wine\\Winetest", 0, 32 );
1549     check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1550     check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1551     pNtClose( key );
1552 
1553     if (ptr_size == 32)
1554     {
1555         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1556         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1557         dw = get_key_value( key, "Wine\\Winetest", 0 );
1558         ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1559         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1560         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1561         pNtClose( key );
1562 
1563         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1564         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1565         check_key_value( key, "Wine\\Winetest", 0, 32 );
1566         check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1567         check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1568         pNtClose( key );
1569     }
1570 
1571     pRtlInitUnicodeString( &str, wine32W );
1572     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1573     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1574     check_key_value( key, "Winetest", 0, 32 );
1575     check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1576     check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1577     pNtClose( key );
1578 
1579     if (ptr_size == 32)
1580     {
1581         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1582         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1583         dw = get_key_value( key, "Winetest", 0 );
1584         ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1585         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1586         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1587         pNtClose( key );
1588 
1589         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1590         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1591         check_key_value( key, "Winetest", 0, 32 );
1592         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1593         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1594         pNtClose( key );
1595     }
1596 
1597     pRtlInitUnicodeString( &str, wine64W );
1598     status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1599     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1600     check_key_value( key, "Winetest", 0, ptr_size );
1601     check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1602     check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1603     pNtClose( key );
1604 
1605     if (ptr_size == 32)
1606     {
1607         status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1608         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1609         dw = get_key_value( key, "Winetest", 0 );
1610         ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1611         check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1612         dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1613         todo_wine ok( dw == 32, "wrong value %u\n", dw );
1614         pNtClose( key );
1615 
1616         status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1617         ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1618         check_key_value( key, "Winetest", 0, 32 );
1619         check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1620         check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1621         pNtClose( key );
1622     }
1623 
1624     status = pNtDeleteKey( key32 );
1625     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1626     pNtClose( key32 );
1627 
1628     status = pNtDeleteKey( key64 );
1629     ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1630     pNtClose( key64 );
1631 
1632     pNtDeleteKey( root32 );
1633     pNtClose( root32 );
1634     pNtDeleteKey( root64 );
1635     pNtClose( root64 );
1636 
1637     /* Software\Classes is shared/reflected so behavior is different */
1638 
1639     pRtlInitUnicodeString( &str, classes64W );
1640     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1641     if (status == STATUS_ACCESS_DENIED)
1642     {
1643         skip("Not authorized to modify the Classes key\n");
1644         return;
1645     }
1646     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1647 
1648     pRtlInitUnicodeString( &str, classes32W );
1649     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1650     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1651 
1652     dw = 64;
1653     status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1654     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1655     pNtClose( key64 );
1656 
1657     dw = 32;
1658     status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1659     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1660     pNtClose( key32 );
1661 
1662     pRtlInitUnicodeString( &str, classes64W );
1663     status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1664     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1665     len = sizeof(buffer);
1666     status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1667     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1668     dw = *(DWORD *)info->Data;
1669     ok( dw == ptr_size, "wrong value %u\n", dw );
1670 
1671     pRtlInitUnicodeString( &str, classes32W );
1672     status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1673     ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1674     len = sizeof(buffer);
1675     status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1676     ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1677     dw = *(DWORD *)info->Data;
1678     ok( dw == 32, "wrong value %u\n", dw );
1679 
1680     pNtDeleteKey( key32 );
1681     pNtClose( key32 );
1682     pNtDeleteKey( key64 );
1683     pNtClose( key64 );
1684 }
1685 
1686 static void test_long_value_name(void)
1687 {
1688     HANDLE key;
1689     NTSTATUS status, expected;
1690     OBJECT_ATTRIBUTES attr;
1691     UNICODE_STRING ValName;
1692     DWORD i;
1693 
1694     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1695     status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1696     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1697 
1698     ValName.MaximumLength = 0xfffc;
1699     ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1700     ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1701     for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1702         ValName.Buffer[i] = 'a';
1703     ValName.Buffer[i] = 0;
1704 
1705     status = pNtDeleteValueKey(key, &ValName);
1706     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1707     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1708     ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1709        "NtSetValueKey with long value name returned 0x%08x\n", status);
1710     expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1711     status = pNtDeleteValueKey(key, &ValName);
1712     ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1713 
1714     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1715     ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1716 
1717     pRtlFreeUnicodeString(&ValName);
1718     pNtClose(key);
1719 }
1720 
1721 static void test_NtQueryKey(void)
1722 {
1723     HANDLE key, subkey, subkey2;
1724     NTSTATUS status;
1725     OBJECT_ATTRIBUTES attr;
1726     ULONG length, len;
1727     KEY_NAME_INFORMATION *info = NULL;
1728     KEY_CACHED_INFORMATION cached_info;
1729     UNICODE_STRING str;
1730     DWORD dw;
1731 
1732     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1733     status = pNtOpenKey(&key, KEY_READ, &attr);
1734     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1735 
1736     status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
1737     if (status == STATUS_INVALID_PARAMETER) {
1738         win_skip("KeyNameInformation is not supported\n");
1739         pNtClose(key);
1740         return;
1741     }
1742     todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1743     info = HeapAlloc(GetProcessHeap(), 0, length);
1744 
1745     /* non-zero buffer size, but insufficient */
1746     status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
1747     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
1748     ok(length == len, "got %d, expected %d\n", len, length);
1749     ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
1750        info->NameLength, winetestpath.Length);
1751 
1752     /* correct buffer size */
1753     status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
1754     ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1755     ok(length == len, "got %d, expected %d\n", len, length);
1756 
1757     str.Buffer = info->Name;
1758     str.Length = info->NameLength;
1759     ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1760        "got %s, expected %s\n",
1761        wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1762        wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1763 
1764     HeapFree(GetProcessHeap(), 0, info);
1765 
1766     attr.RootDirectory = key;
1767     attr.ObjectName = &str;
1768     pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1769     status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1770     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1771     pRtlFreeUnicodeString(&str);
1772 
1773     status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1774     ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1775 
1776     if (status == STATUS_SUCCESS)
1777     {
1778         ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1779         ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1780         ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1781         ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
1782         ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1783         ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1784         ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1785     }
1786 
1787     attr.RootDirectory = subkey;
1788     attr.ObjectName = &str;
1789     pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
1790     status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
1791     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1792     pRtlFreeUnicodeString(&str);
1793 
1794     pRtlCreateUnicodeStringFromAsciiz(&str, "val");
1795     dw = 64;
1796     status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
1797     ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1798     pRtlFreeUnicodeString(&str);
1799 
1800     if (!winetest_interactive)
1801         skip("ROSTESTS-198: Causes an assert in Cm.\n");
1802     else
1803     {
1804         status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1805         ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1806 
1807         if (status == STATUS_SUCCESS)
1808         {
1809             ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1810             ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1811             ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1812             ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
1813             ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1814             ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1815             ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1816         }
1817     }
1818 
1819     status = pNtDeleteKey(subkey2);
1820     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1821     status = pNtDeleteKey(subkey);
1822     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1823 
1824     pNtClose(subkey2);
1825     pNtClose(subkey);
1826     pNtClose(key);
1827 }
1828 
1829 static void test_notify(void)
1830 {
1831     OBJECT_ATTRIBUTES attr;
1832     LARGE_INTEGER timeout;
1833     IO_STATUS_BLOCK iosb;
1834     UNICODE_STRING str;
1835     HANDLE key, events[2], subkey;
1836     NTSTATUS status;
1837 
1838     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1839     status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1840     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1841 
1842     events[0] = CreateEventW(NULL, FALSE, TRUE, NULL);
1843     ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError());
1844     events[1] = CreateEventW(NULL, FALSE, TRUE, NULL);
1845     ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError());
1846 
1847     status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1848     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1849     status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1850     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1851 
1852     timeout.QuadPart = 0;
1853     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1854     ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1855     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1856     ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1857 
1858     attr.RootDirectory = key;
1859     attr.ObjectName = &str;
1860 
1861     pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1862     status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1863     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1864     pRtlFreeUnicodeString(&str);
1865 
1866     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1867     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1868     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1869     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1870 
1871     status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1872     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1873     status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1874     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1875 
1876     status = pNtDeleteKey(subkey);
1877     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1878 
1879     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1880     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1881     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1882     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1883 
1884     pNtClose(subkey);
1885 
1886     status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1887     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1888     status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1889     ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1890 
1891     pNtClose(key);
1892 
1893     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1894     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1895     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1896     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1897 
1898     if (pNtNotifyChangeMultipleKeys)
1899     {
1900         InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1901         status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1902         ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1903 
1904         status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1905         ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1906 
1907         timeout.QuadPart = 0;
1908         status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1909         ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1910 
1911         attr.RootDirectory = key;
1912         attr.ObjectName = &str;
1913         pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1914         status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1915         ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1916         pRtlFreeUnicodeString(&str);
1917 
1918         status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1919         ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1920 
1921         status = pNtDeleteKey(subkey);
1922         ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1923         pNtClose(subkey);
1924         pNtClose(key);
1925     }
1926     else
1927     {
1928         win_skip("NtNotifyChangeMultipleKeys not available\n");
1929     }
1930 
1931     pNtClose(events[0]);
1932     pNtClose(events[1]);
1933 }
1934 
1935 START_TEST(reg)
1936 {
1937     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1938     if(!InitFunctionPtrs())
1939         return;
1940     pRtlFormatCurrentUserKeyPath(&winetestpath);
1941     winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1942                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1943     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1944 
1945     pRtlAppendUnicodeToString(&winetestpath, winetest);
1946 
1947     test_NtCreateKey();
1948     test_NtOpenKey();
1949     test_NtSetValueKey();
1950     test_RtlCheckRegistryKey();
1951     test_RtlOpenCurrentUser();
1952     test_RtlQueryRegistryValues();
1953     test_RtlpNtQueryValueKey();
1954     test_NtFlushKey();
1955     test_NtQueryKey();
1956     test_NtQueryLicenseKey();
1957     test_NtQueryValueKey();
1958     test_long_value_name();
1959     test_notify();
1960     test_NtDeleteKey();
1961     test_symlinks();
1962     test_redirection();
1963 
1964     pRtlFreeUnicodeString(&winetestpath);
1965 
1966     FreeLibrary(hntdll);
1967 }
1968