ntdll: Fix NtQueryValueKey for KeyValueBasicInformation.
[wine] / dlls / ntdll / tests / reg.c
1 /* Unit test suite for Rtl* Registry API functions
2  *
3  * Copyright 2003 Thomas Mertes
4  * Copyright 2005 Brad DeMorrow
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through
21  * helper function RTL_GetKeyHandle().--Brad DeMorrow
22  *
23  */
24
25 #include "ntdll_test.h"
26 #include "winternl.h"
27 #include "stdio.h"
28 #include "winnt.h"
29 #include "winnls.h"
30 #include "stdlib.h"
31
32 #ifndef __WINE_WINTERNL_H
33
34 /* RtlQueryRegistryValues structs and defines */
35 #define RTL_REGISTRY_ABSOLUTE             0
36 #define RTL_REGISTRY_SERVICES             1
37 #define RTL_REGISTRY_CONTROL              2
38 #define RTL_REGISTRY_WINDOWS_NT           3
39 #define RTL_REGISTRY_DEVICEMAP            4
40 #define RTL_REGISTRY_USER                 5
41
42 #define RTL_REGISTRY_HANDLE       0x40000000
43 #define RTL_REGISTRY_OPTIONAL     0x80000000
44
45 #define RTL_QUERY_REGISTRY_SUBKEY         0x00000001
46 #define RTL_QUERY_REGISTRY_TOPKEY         0x00000002
47 #define RTL_QUERY_REGISTRY_REQUIRED       0x00000004
48 #define RTL_QUERY_REGISTRY_NOVALUE        0x00000008
49 #define RTL_QUERY_REGISTRY_NOEXPAND       0x00000010
50 #define RTL_QUERY_REGISTRY_DIRECT         0x00000020
51 #define RTL_QUERY_REGISTRY_DELETE         0x00000040
52
53 typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR  ValueName,
54                                                         ULONG  ValueType,
55                                                         PVOID  ValueData,
56                                                         ULONG  ValueLength,
57                                                         PVOID  Context,
58                                                         PVOID  EntryContext);
59
60 typedef struct _RTL_QUERY_REGISTRY_TABLE {
61   PRTL_QUERY_REGISTRY_ROUTINE  QueryRoutine;
62   ULONG  Flags;
63   PWSTR  Name;
64   PVOID  EntryContext;
65   ULONG  DefaultType;
66   PVOID  DefaultData;
67   ULONG  DefaultLength;
68 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
69
70 typedef struct _KEY_VALUE_BASIC_INFORMATION {
71     ULONG TitleIndex;
72     ULONG Type;
73     ULONG NameLength;
74     WCHAR Name[1];
75 } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
76
77 typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
78     ULONG TitleIndex;
79     ULONG Type;
80     ULONG DataLength;
81     UCHAR Data[1];
82 } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
83
84 typedef struct _KEY_VALUE_FULL_INFORMATION {
85     ULONG TitleIndex;
86     ULONG Type;
87     ULONG DataOffset;
88     ULONG DataLength;
89     ULONG NameLength;
90     WCHAR Name[1];
91 } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
92
93 typedef enum _KEY_VALUE_INFORMATION_CLASS {
94     KeyValueBasicInformation,
95     KeyValueFullInformation,
96     KeyValuePartialInformation,
97     KeyValueFullInformationAlign64,
98     KeyValuePartialInformationAlign64
99 } KEY_VALUE_INFORMATION_CLASS;
100
101 #define InitializeObjectAttributes(p,n,a,r,s) \
102     do { \
103         (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
104         (p)->RootDirectory = r; \
105         (p)->Attributes = a; \
106         (p)->ObjectName = n; \
107         (p)->SecurityDescriptor = s; \
108         (p)->SecurityQualityOfService = NULL; \
109     } while (0)
110
111 #endif
112
113 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
114 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
115 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
116 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
117 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
118 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY);
119 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
120 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
121 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
122 static NTSTATUS (WINAPI * pNtFlushKey)(HKEY);
123 static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY);
124 static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
125                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
126                              PULONG dispos );
127 static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
128 static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG,
129                                ULONG, const PVOID, ULONG  );
130 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
131 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
132 static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
133 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
134 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
135 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
136 static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
137 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
138 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*);
139
140 static HMODULE hntdll = 0;
141 static int CurrentTest = 0;
142 static UNICODE_STRING winetestpath;
143
144 #define NTDLL_GET_PROC(func) \
145     p ## func = (void*)GetProcAddress(hntdll, #func); \
146     if(!p ## func) { \
147         trace("GetProcAddress(%s) failed\n", #func); \
148         FreeLibrary(hntdll); \
149         return FALSE; \
150     }
151
152 static BOOL InitFunctionPtrs(void)
153 {
154     hntdll = LoadLibraryA("ntdll.dll");
155     if(!hntdll) {
156         trace("Could not load ntdll.dll\n");
157         return FALSE;
158     }
159     if (hntdll)
160     {
161         NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
162         NTDLL_GET_PROC(RtlCreateUnicodeString)
163         NTDLL_GET_PROC(RtlFreeUnicodeString)
164         NTDLL_GET_PROC(NtDeleteValueKey)
165         NTDLL_GET_PROC(RtlQueryRegistryValues)
166         NTDLL_GET_PROC(RtlCheckRegistryKey)
167         NTDLL_GET_PROC(RtlOpenCurrentUser)
168         NTDLL_GET_PROC(NtClose)
169         NTDLL_GET_PROC(NtDeleteValueKey)
170         NTDLL_GET_PROC(NtCreateKey)
171         NTDLL_GET_PROC(NtFlushKey)
172         NTDLL_GET_PROC(NtDeleteKey)
173         NTDLL_GET_PROC(NtQueryValueKey)
174         NTDLL_GET_PROC(NtSetValueKey)
175         NTDLL_GET_PROC(NtOpenKey)
176         NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
177         NTDLL_GET_PROC(RtlReAllocateHeap)
178         NTDLL_GET_PROC(RtlAppendUnicodeToString)
179         NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
180         NTDLL_GET_PROC(RtlFreeHeap)
181         NTDLL_GET_PROC(RtlAllocateHeap)
182         NTDLL_GET_PROC(RtlZeroMemory)
183         NTDLL_GET_PROC(RtlpNtQueryValueKey)
184     }
185     return TRUE;
186 }
187 #undef NTDLL_GET_PROC
188
189 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
190                               IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
191 {
192     NTSTATUS ret = STATUS_SUCCESS;
193     int ValueNameLength = 0;
194     LPSTR ValName = 0;
195     trace("**Test %d**\n", CurrentTest);
196
197     if(ValueName)
198     {
199         ValueNameLength = lstrlenW(ValueName);
200
201         ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
202
203         WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
204
205         trace("ValueName: %s\n", ValName);
206     }
207     else
208         trace("ValueName: (null)\n");
209
210     switch(ValueType)
211     {
212             case REG_NONE:
213                 trace("ValueType: REG_NONE\n");
214                 trace("ValueData: %d\n", (int)ValueData);
215                 break;
216
217             case REG_BINARY:
218                 trace("ValueType: REG_BINARY\n");
219                 trace("ValueData: %d\n", (int)ValueData);
220                 break;
221
222             case REG_SZ:
223                 trace("ValueType: REG_SZ\n");
224                 trace("ValueData: %s\n", (char*)ValueData);
225                 break;
226
227             case REG_MULTI_SZ:
228                 trace("ValueType: REG_MULTI_SZ\n");
229                 trace("ValueData: %s\n", (char*)ValueData);
230                 break;
231
232             case REG_EXPAND_SZ:
233                 trace("ValueType: REG_EXPAND_SZ\n");
234                 trace("ValueData: %s\n", (char*)ValueData);
235                 break;
236
237             case REG_DWORD:
238                 trace("ValueType: REG_DWORD\n");
239                 trace("ValueData: %d\n", (int)ValueData);
240                 break;
241     };
242     trace("ValueLength: %d\n", (int)ValueLength);
243
244     if(CurrentTest == 0)
245         ok(1, "\n"); /*checks that QueryRoutine is called*/
246     if(CurrentTest > 7)
247         ok(!1, "Invalid Test Specified!\n");
248
249     CurrentTest++;
250
251     if(ValName)
252         pRtlFreeHeap(GetProcessHeap(), 0, ValName);
253
254     return ret;
255 }
256
257 static void test_RtlQueryRegistryValues(void)
258 {
259
260     /*
261     ******************************
262     *       QueryTable Flags     *
263     ******************************
264     *RTL_QUERY_REGISTRY_SUBKEY   * Name is the name of a subkey relative to Path
265     *RTL_QUERY_REGISTRY_TOPKEY   * Resets location to original RelativeTo and Path
266     *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
267     *RTL_QUERY_REGISTRY_NOVALUE  * We just want a call-back
268     *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
269     *RTL_QUERY_REGISTRY_DIRECT   * Results of query will be stored in EntryContext(QueryRoutine ignored)
270     *RTL_QUERY_REGISTRY_DELETE   * Delete value key after query
271     ******************************
272
273
274     **Test layout(numbered according to CurrentTest value)**
275     0)NOVALUE           Just make sure call-back works
276     1)Null Name         See if QueryRoutine is called for every value in current key
277     2)SUBKEY            See if we can use SUBKEY to change the current path on the fly
278     3)REQUIRED          Test for value that's not there
279     4)NOEXPAND          See if it will return multiple strings(no expand should split strings up)
280     5)DIRECT            Make it store data directly in EntryContext and not call QueryRoutine
281     6)DefaultType       Test return values when key isn't present
282     7)DefaultValue      Test Default Value returned with key isn't present(and no REQUIRED flag set)
283     8)DefaultLength     Test Default Length with DefaultType = REG_SZ
284    9)DefaultLength      Test Default Length with DefaultType = REG_MULTI_SZ
285    10)DefaultLength     Test Default Length with DefaultType = REG_EXPAND_SZ
286    11)DefaultData       Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be)
287    12)Delete            Try to delete value key
288
289     */
290     NTSTATUS status;
291     ULONG RelativeTo;
292
293     PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
294     RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
295
296     QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
297
298     pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
299
300     QueryTable[0].QueryRoutine = QueryRoutine;
301     QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
302     QueryTable[0].Name = NULL;
303     QueryTable[0].EntryContext = NULL;
304     QueryTable[0].DefaultType = REG_BINARY;
305     QueryTable[0].DefaultData = NULL;
306     QueryTable[0].DefaultLength = 100;
307
308     QueryTable[1].QueryRoutine = QueryRoutine;
309     QueryTable[1].Flags = 0;
310     QueryTable[1].Name = NULL;
311     QueryTable[1].EntryContext = 0;
312     QueryTable[1].DefaultType = REG_NONE;
313     QueryTable[1].DefaultData = NULL;
314     QueryTable[1].DefaultLength = 0;
315
316     QueryTable[2].QueryRoutine = NULL;
317     QueryTable[2].Flags = 0;
318     QueryTable[2].Name = NULL;
319     QueryTable[2].EntryContext = 0;
320     QueryTable[2].DefaultType = REG_NONE;
321     QueryTable[2].DefaultData = NULL;
322     QueryTable[2].DefaultLength = 0;
323
324     status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
325     ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
326
327     pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
328 }
329
330 static void test_NtOpenKey(void)
331 {
332     HANDLE key;
333     NTSTATUS status;
334     OBJECT_ATTRIBUTES attr;
335     ACCESS_MASK am = KEY_READ;
336
337     if (0)
338     {
339     /* Crashes Wine */
340     /* All NULL */
341     status = pNtOpenKey(NULL, 0, NULL);
342     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
343
344     /* NULL attributes */
345     status = pNtOpenKey(&key, 0, NULL);
346     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
347         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
348     }
349
350     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
351
352     /* NULL key */
353     status = pNtOpenKey(NULL, 0, &attr);
354     todo_wine
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     todo_wine
361         ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
362 }
363
364 static void test_NtCreateKey(void)
365 {
366     /*Create WineTest*/
367     OBJECT_ATTRIBUTES attr;
368     HKEY key;
369     ACCESS_MASK am = GENERIC_ALL;
370     NTSTATUS status;
371
372     /* All NULL */
373     status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
374     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
375
376     /* Only the key */
377     status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
378     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
379         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
380
381     /* Only accessmask */
382     status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
383     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
384
385     /* Key and accessmask */
386     status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
387     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
388         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
389
390     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
391
392     /* Only attributes */
393     status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
394     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
395
396     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
397     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
398
399     /* Length > sizeof(OBJECT_ATTRIBUTES) */
400     attr.Length *= 2;
401     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
402     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
403
404     pNtClose(key);
405 }
406
407 static void test_NtSetValueKey(void)
408 {
409     HANDLE key;
410     NTSTATUS status;
411     OBJECT_ATTRIBUTES attr;
412     ACCESS_MASK am = KEY_WRITE;
413     UNICODE_STRING ValName;
414     DWORD data = 711;
415
416     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
417
418     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
419     status = pNtOpenKey(&key, am, &attr);
420     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
421
422     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
423     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
424
425     pRtlFreeUnicodeString(&ValName);
426     pNtClose(key);
427 }
428
429 static void test_RtlOpenCurrentUser(void)
430 {
431     NTSTATUS status;
432     HKEY handle;
433     status=pRtlOpenCurrentUser(KEY_READ, &handle);
434     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
435     pNtClose(handle);
436 }
437
438 static void test_RtlCheckRegistryKey(void)
439 {
440     NTSTATUS status;
441
442     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
443     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
444
445     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
446     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
447 }
448
449 static void test_NtFlushKey(void)
450 {
451     NTSTATUS status;
452     HANDLE hkey;
453     OBJECT_ATTRIBUTES attr;
454     ACCESS_MASK am = KEY_ALL_ACCESS;
455
456     status = pNtFlushKey(NULL);
457     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
458
459     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
460     pNtOpenKey(&hkey, am, &attr);
461
462     status = pNtFlushKey(hkey);
463     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
464
465     pNtClose(hkey);
466 }
467
468 static void test_NtQueryValueKey(void)
469 {
470     HANDLE key;
471     NTSTATUS status;
472     OBJECT_ATTRIBUTES attr;
473     UNICODE_STRING ValName;
474     KEY_VALUE_BASIC_INFORMATION *basic_info;
475     KEY_VALUE_PARTIAL_INFORMATION *partial_info;
476     KEY_VALUE_FULL_INFORMATION *full_info;
477     DWORD len;
478
479     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
480
481     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
482     status = pNtOpenKey(&key, KEY_READ, &attr);
483     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
484
485     len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
486     basic_info = HeapAlloc(GetProcessHeap(), 0, len);
487     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
488     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
489     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->Type);
490     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
491     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
492     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
493
494     basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
495     status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
496     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
497     ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->Type);
498     ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
499     ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
500     ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
501     ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
502     HeapFree(GetProcessHeap(), 0, basic_info);
503
504     len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
505     partial_info = HeapAlloc(GetProcessHeap(), 0, len);
506     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
507     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
508     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->Type);
509     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
510     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
511     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
512
513     partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
514     status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
515     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
516     ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->Type);
517     ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
518     ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
519     ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
520     ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
521     HeapFree(GetProcessHeap(), 0, partial_info);
522
523     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
524     full_info = HeapAlloc(GetProcessHeap(), 0, len);
525     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
526     ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
527     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->Type);
528     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
529     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
530     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
531     ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
532         "NtQueryValueKey returned wrong len %d\n", len);
533     len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
534
535     full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
536     status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
537     ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
538     ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->Type);
539     ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
540     ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
541     ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
542     ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
543     ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
544         *(DWORD *)((char *)full_info + full_info->DataOffset));
545     HeapFree(GetProcessHeap(), 0, full_info);
546
547     pRtlFreeUnicodeString(&ValName);
548     pNtClose(key);
549 }
550
551 static void test_NtDeleteKey(void)
552 {
553     NTSTATUS status;
554     HANDLE hkey;
555     OBJECT_ATTRIBUTES attr;
556     ACCESS_MASK am = KEY_ALL_ACCESS;
557
558     status = pNtDeleteKey(NULL);
559     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
560
561     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
562     status = pNtOpenKey(&hkey, am, &attr);
563
564     status = pNtDeleteKey(hkey);
565     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
566 }
567
568 static void test_RtlpNtQueryValueKey(void)
569 {
570     NTSTATUS status;
571
572     status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL);
573     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
574 }
575
576 START_TEST(reg)
577 {
578     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0};
579     if(!InitFunctionPtrs())
580         return;
581     pRtlFormatCurrentUserKeyPath(&winetestpath);
582     winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
583                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
584     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
585
586     pRtlAppendUnicodeToString(&winetestpath, winetest);
587
588     test_NtOpenKey();
589     test_NtCreateKey();
590     test_NtSetValueKey();
591     test_RtlCheckRegistryKey();
592     test_RtlOpenCurrentUser();
593     test_RtlQueryRegistryValues();
594     test_RtlpNtQueryValueKey();
595     test_NtFlushKey();
596     test_NtQueryValueKey();
597     test_NtDeleteKey();
598
599     pRtlFreeUnicodeString(&winetestpath);
600
601     FreeLibrary(hntdll);
602 }