Reverse the order for deleting the items in resetcontent to correctly
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wine/library.h"
28 #include "stdio.h"
29 #include "winnt.h"
30 #include "winnls.h"
31 #include "stdlib.h"
32 #include "wine/unicode.h"
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 #endif
73
74 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
75 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
76 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
77 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
78 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
79 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY);
80 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
81 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
82 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
83 static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY);
84 static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
85                              ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
86                              PULONG dispos );
87 static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG,
88                                ULONG, const PVOID, ULONG  );
89 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
90 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
91 static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
92 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
93 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
94 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
95 static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
96 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
97
98 static HMODULE hntdll = 0;
99 static int CurrentTest = 0;
100 static UNICODE_STRING winetestpath;
101
102 static void InitFunctionPtrs(void)
103 {
104     hntdll = LoadLibraryA("ntdll.dll");
105     ok(hntdll != 0, "LoadLibrary failed\n");
106     if (hntdll)
107     {
108         pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz");
109         pRtlCreateUnicodeString = (void*)GetProcAddress(hntdll, "RtlCreateUnicodeString");
110         pRtlFreeUnicodeString = (void*)GetProcAddress(hntdll, "RtlFreeUnicodeString");
111         pNtDeleteValueKey = (void*)GetProcAddress(hntdll, "NtDeleteValueKey");
112         pRtlQueryRegistryValues = (void*)GetProcAddress(hntdll, "RtlQueryRegistryValues");
113         pRtlCheckRegistryKey = (void*)GetProcAddress(hntdll, "RtlCheckRegistryKey");
114         pRtlOpenCurrentUser = (void*)GetProcAddress(hntdll, "RtlOpenCurrentUser");
115         pNtClose = (void*)GetProcAddress(hntdll, "NtClose");
116         pNtDeleteValueKey = (void*)GetProcAddress(hntdll, "NtDeleteValueKey");
117         pNtCreateKey = (void*)GetProcAddress(hntdll, "NtCreateKey");
118         pNtDeleteKey = (void*)GetProcAddress(hntdll, "NtDeleteKey");
119         pNtSetValueKey = (void*)GetProcAddress(hntdll, "NtSetValueKey");
120         pNtOpenKey = (void*)GetProcAddress(hntdll, "NtOpenKey");
121         pRtlFormatCurrentUserKeyPath = (void*)GetProcAddress(hntdll, "RtlFormatCurrentUserKeyPath");
122         pRtlReAllocateHeap = (void*)GetProcAddress(hntdll, "RtlReAllocateHeap");
123         pRtlAppendUnicodeToString = (void*)GetProcAddress(hntdll, "RtlAppendUnicodeToString");
124         pRtlUnicodeStringToAnsiString = (void*)GetProcAddress(hntdll, "RtlUnicodeStringToAnsiString");
125         pRtlFreeHeap = (void*)GetProcAddress(hntdll, "RtlFreeHeap");
126         pRtlAllocateHeap = (void*)GetProcAddress(hntdll, "RtlAllocateHeap");
127         pRtlZeroMemory = (void*)GetProcAddress(hntdll, "RtlZeroMemory");
128     }
129
130
131 }
132
133 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
134                               IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
135 {
136     NTSTATUS ret = STATUS_SUCCESS;
137     int ValueNameLength = 0;
138     LPSTR ValName = 0;
139     trace("**Test %d**\n", CurrentTest);
140
141     if(ValueName)
142     {
143         ValueNameLength = strlenW(ValueName);
144
145         ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
146
147         WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
148
149         trace("ValueName: %s\n", ValName);
150     }
151     else
152         trace("ValueName: (null)\n");
153
154     switch(ValueType)
155     {
156             case REG_NONE:
157                 trace("ValueType: REG_NONE\n");
158                 trace("ValueData: %d\n", (int)ValueData);
159                 break;
160
161             case REG_BINARY:
162                 trace("ValueType: REG_BINARY\n");
163                 trace("ValueData: %d\n", (int)ValueData);
164                 break;
165
166             case REG_SZ:
167                 trace("ValueType: REG_SZ\n");
168                 trace("ValueData: %s\n", (char*)ValueData);
169                 break;
170
171             case REG_MULTI_SZ:
172                 trace("ValueType: REG_MULTI_SZ\n");
173                 trace("ValueData: %s\n", (char*)ValueData);
174                 break;
175
176             case REG_EXPAND_SZ:
177                 trace("ValueType: REG_EXPAND_SZ\n");
178                 trace("ValueData: %s\n", (char*)ValueData);
179                 break;
180
181             case REG_DWORD:
182                 trace("ValueType: REG_DWORD\n");
183                 trace("ValueData: %d\n", (int)ValueData);
184                 break;
185     };
186     trace("ValueLength: %d\n", (int)ValueLength);
187
188     if(CurrentTest == 0)
189         ok(1, "\n"); /*checks that QueryRoutine is called*/
190     if(CurrentTest > 7)
191         ok(!1, "Invalid Test Specified!\n");
192
193     CurrentTest++;
194
195     if(ValName)
196         pRtlFreeHeap(GetProcessHeap(), 0, ValName);
197
198     return ret;
199 }
200
201 static void test_RtlQueryRegistryValues(void)
202 {
203
204     /*
205     ******************************
206     *       QueryTable Flags     *
207     ******************************
208     *RTL_QUERY_REGISTRY_SUBKEY   * Name is the name of a subkey relative to Path
209     *RTL_QUERY_REGISTRY_TOPKEY   * Resets location to original RelativeTo and Path
210     *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
211     *RTL_QUERY_REGISTRY_NOVALUE  * We just want a call-back
212     *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
213     *RTL_QUERY_REGISTRY_DIRECT   * Results of query will be stored in EntryContext(QueryRoutine ignored)
214     *RTL_QUERY_REGISTRY_DELETE   * Delete value key after query
215     ******************************
216
217
218     **Test layout(numbered according to CurrentTest value)**
219     0)NOVALUE           Just make sure call-back works
220     1)Null Name         See if QueryRoutine is called for every value in current key
221     2)SUBKEY            See if we can use SUBKEY to change the current path on the fly
222     3)REQUIRED          Test for value that's not there
223     4)NOEXPAND          See if it will return multiple strings(no expand should split strings up)
224     5)DIRECT            Make it store data directly in EntryContext and not call QueryRoutine
225     6)DefaultType       Test return values when key isn't present
226     7)DefaultValue      Test Default Value returned with key isn't present(and no REQUIRED flag set)
227     8)DefaultLength     Test Default Length with DefaultType = REG_SZ
228    9)DefaultLength      Test Default Length with DefaultType = REG_MULTI_SZ
229    10)DefaultLength     Test Default Length with DefaultType = REG_EXPAND_SZ
230    11)DefaultData       Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be)
231    12)Delete            Try to delete value key
232
233     */
234     NTSTATUS status;
235     ULONG RelativeTo;
236
237     PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
238     RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
239
240     QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
241
242     pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
243
244     QueryTable[0].QueryRoutine = QueryRoutine;
245     QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
246     QueryTable[0].Name = NULL;
247     QueryTable[0].EntryContext = NULL;
248     QueryTable[0].DefaultType = REG_BINARY;
249     QueryTable[0].DefaultData = NULL;
250     QueryTable[0].DefaultLength = 100;
251
252     QueryTable[1].QueryRoutine = QueryRoutine;
253     QueryTable[1].Flags = 0;
254     QueryTable[1].Name = NULL;
255     QueryTable[1].EntryContext = 0;
256     QueryTable[1].DefaultType = REG_NONE;
257     QueryTable[1].DefaultData = NULL;
258     QueryTable[1].DefaultLength = 0;
259
260     QueryTable[2].QueryRoutine = NULL;
261     QueryTable[2].Flags = 0;
262     QueryTable[2].Name = NULL;
263     QueryTable[2].EntryContext = 0;
264     QueryTable[2].DefaultType = REG_NONE;
265     QueryTable[2].DefaultData = NULL;
266     QueryTable[2].DefaultLength = 0;
267
268     status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
269     ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08lx\n", status);
270
271     pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
272 }
273
274 static void test_NtCreateKey(void)
275 {
276     /*Create WineTest*/
277     OBJECT_ATTRIBUTES attr;
278     UNICODE_STRING ValName;
279     HKEY key;
280     ACCESS_MASK am = GENERIC_ALL;
281     NTSTATUS status;
282
283     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
284     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
285     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\n", status);
286
287     pRtlFreeUnicodeString(&ValName);
288     pNtClose(&key);
289 }
290
291 static void test_NtSetValueKey(void)
292 {
293     HANDLE key;
294     NTSTATUS status;
295     OBJECT_ATTRIBUTES attr;
296     ACCESS_MASK am = KEY_WRITE;
297     UNICODE_STRING ValName;
298     DWORD data = 711;
299
300     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
301
302     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
303     status = pNtOpenKey(&key, am, &attr);
304     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
305
306     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
307     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status);
308
309     pRtlFreeUnicodeString(&ValName);
310     pNtClose(&key);
311 }
312
313 static void test_RtlOpenCurrentUser(void)
314 {
315     NTSTATUS status;
316     HKEY handle;
317     status=pRtlOpenCurrentUser(KEY_READ, &handle);
318     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08lx\n", status);
319     pNtClose(&handle);
320 }
321
322 static void test_RtlCheckRegistryKey(void)
323 {
324     NTSTATUS status;
325
326     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
327     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\n", status);
328
329     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE & RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
330     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE & RTL_REGISTRY_OPTIONAL: 0x%08lx\n", status);
331 }
332
333 static void test_NtDeleteKey()
334 {
335     NTSTATUS status;
336     HANDLE hkey;
337     OBJECT_ATTRIBUTES attr;
338     ACCESS_MASK am = KEY_ALL_ACCESS;
339
340     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
341     status = pNtOpenKey(&hkey, am, &attr);
342
343     status = pNtDeleteKey(hkey);
344     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
345 }
346
347 START_TEST(reg)
348 {
349     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0};
350     InitFunctionPtrs();
351     pRtlFormatCurrentUserKeyPath(&winetestpath);
352     winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
353                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
354     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
355
356     pRtlAppendUnicodeToString(&winetestpath, winetest);
357
358     test_NtCreateKey();
359     test_NtSetValueKey();
360     test_RtlCheckRegistryKey();
361     test_RtlOpenCurrentUser();
362     test_RtlQueryRegistryValues();
363     test_NtDeleteKey();
364
365     pRtlFreeUnicodeString(&winetestpath);
366
367     FreeLibrary(hntdll);
368 }