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