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