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