Show the value, not the address in memory! (Thanks to Dmitry Philippov)
[reactos.git] / reactos / regtests / winetests / ntdll / reg.c
1 /* Unit test suite for Rtl* Registry API functions
2 *
3 * Copyright 2003 Thomas Mertes
4 * Copyright 2005 Brad DeMorrow
5 * Copyright 2006 Dmitry Philippov
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through
22 * helper function RTL_GetKeyHandle().--Brad DeMorrow
23 *
24 */
25
26 #include "ntdll_test.h"
27 #include "winternl.h"
28 #include "stdio.h"
29 #include "winnt.h"
30 #include "winnls.h"
31 #include "stdlib.h"
32
33 #ifndef __WINE_WINTERNL_H
34
35 /* RtlQueryRegistryValues structs and defines */
36 #define RTL_REGISTRY_ABSOLUTE 0
37 #define RTL_REGISTRY_SERVICES 1
38 #define RTL_REGISTRY_CONTROL 2
39 #define RTL_REGISTRY_WINDOWS_NT 3
40 #define RTL_REGISTRY_DEVICEMAP 4
41 #define RTL_REGISTRY_USER 5
42
43 #define RTL_REGISTRY_HANDLE 0x40000000
44 #define RTL_REGISTRY_OPTIONAL 0x80000000
45
46 #define RTL_QUERY_REGISTRY_SUBKEY 0x00000001
47 #define RTL_QUERY_REGISTRY_TOPKEY 0x00000002
48 #define RTL_QUERY_REGISTRY_REQUIRED 0x00000004
49 #define RTL_QUERY_REGISTRY_NOVALUE 0x00000008
50 #define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010
51 #define RTL_QUERY_REGISTRY_DIRECT 0x00000020
52 #define RTL_QUERY_REGISTRY_DELETE 0x00000040
53
54 typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR ValueName,
55 ULONG ValueType,
56 PVOID ValueData,
57 ULONG ValueLength,
58 PVOID Context,
59 PVOID EntryContext);
60
61 typedef struct _RTL_QUERY_REGISTRY_TABLE {
62 PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
63 ULONG Flags;
64 PWSTR Name;
65 PVOID EntryContext;
66 ULONG DefaultType;
67 PVOID DefaultData;
68 ULONG DefaultLength;
69 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
70
71 #define InitializeObjectAttributes(p,n,a,r,s) \
72 do { \
73 (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
74 (p)->RootDirectory = r; \
75 (p)->Attributes = a; \
76 (p)->ObjectName = n; \
77 (p)->SecurityDescriptor = s; \
78 (p)->SecurityQualityOfService = NULL; \
79 } while (0)
80
81 #endif
82
83 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
84 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
85 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
86 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
87 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
88 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHANDLE);
89 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
90 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
91 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
92 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
93 static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
94 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
95 PULONG dispos );
96 static NTSTATUS (WINAPI * pNtSetValueKey)( HANDLE, const PUNICODE_STRING, ULONG,
97 ULONG, const PVOID, ULONG );
98 static NTSTATUS (WINAPI * pNtQueryValueKey)( HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,
99 void *,DWORD,DWORD * );
100 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
101 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
102 static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
103 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
104 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
105 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
106 static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
107 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
108
109 static HMODULE hntdll = 0;
110 static int CurrentTest = 0;
111 static UNICODE_STRING winetestpath;
112
113 #define NTDLL_GET_PROC(func) \
114 p ## func = (void*)GetProcAddress(hntdll, #func); \
115 if(!p ## func) { \
116 trace("GetProcAddress(%s) failed\n", #func); \
117 FreeLibrary(hntdll); \
118 return FALSE; \
119 }
120
121 static BOOL InitFunctionPtrs(void)
122 {
123 hntdll = LoadLibraryA("ntdll.dll");
124 if(!hntdll) {
125 trace("Could not load ntdll.dll\n");
126 return FALSE;
127 }
128 if (hntdll)
129 {
130 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
131 NTDLL_GET_PROC(RtlCreateUnicodeString)
132 NTDLL_GET_PROC(RtlFreeUnicodeString)
133 NTDLL_GET_PROC(NtDeleteValueKey)
134 NTDLL_GET_PROC(RtlQueryRegistryValues)
135 NTDLL_GET_PROC(RtlCheckRegistryKey)
136 NTDLL_GET_PROC(RtlOpenCurrentUser)
137 NTDLL_GET_PROC(NtClose)
138 NTDLL_GET_PROC(NtDeleteValueKey)
139 NTDLL_GET_PROC(NtCreateKey)
140 NTDLL_GET_PROC(NtDeleteKey)
141 NTDLL_GET_PROC(NtSetValueKey)
142 NTDLL_GET_PROC(NtQueryValueKey)
143 NTDLL_GET_PROC(NtOpenKey)
144 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
145 NTDLL_GET_PROC(RtlReAllocateHeap)
146 NTDLL_GET_PROC(RtlAppendUnicodeToString)
147 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
148 NTDLL_GET_PROC(RtlFreeHeap)
149 NTDLL_GET_PROC(RtlAllocateHeap)
150 NTDLL_GET_PROC(RtlZeroMemory)
151 }
152 return TRUE;
153 }
154 #undef NTDLL_GET_PROC
155
156 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
157 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
158 {
159 NTSTATUS ret = STATUS_SUCCESS;
160 LPSTR ValName = 0;
161 LPSTR ValData = 0;
162 int ValueNameLength = 0;
163 trace("**Test %d**\n", CurrentTest);
164
165 if(ValueName)
166 {
167 ValueNameLength = lstrlenW(ValueName);
168
169 ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
170 WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
171
172 trace("ValueName: %s\n", ValName);
173 }
174 else
175 trace("ValueName: (null)\n");
176
177 if( ValueType == REG_SZ ||
178 ValueType == REG_MULTI_SZ ||
179 ValueType == REG_EXPAND_SZ )
180 {
181 ValData = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueLength);
182 WideCharToMultiByte(0, 0, ValueData, ValueLength, ValData, ValueLength, 0, 0);
183 }
184
185 switch(ValueType)
186 {
187 case REG_NONE:
188 trace("ValueType: REG_NONE\n");
189 trace("ValueData: %d\n", (int)ValueData);
190 break;
191
192 case REG_BINARY:
193 trace("ValueType: REG_BINARY\n");
194 trace("ValueData: %d\n", *(unsigned int *)ValueData);
195 break;
196
197 case REG_SZ:
198 trace("ValueType: REG_SZ\n");
199 trace("ValueData: %s\n", ValData);
200 break;
201
202 case REG_MULTI_SZ:
203 trace("ValueType: REG_MULTI_SZ\n");
204 trace("ValueData: %s", (char*)ValData);
205 break;
206
207 case REG_EXPAND_SZ:
208 trace("ValueType: REG_EXPAND_SZ\n");
209 trace("ValueData: %s\n", (char*)ValData);
210 break;
211
212 case REG_DWORD:
213 trace("ValueType: REG_DWORD\n");
214 trace("ValueData: %d\n", *(unsigned int *)ValueData);
215 break;
216 };
217 trace("ValueLength: %d\n", (int)ValueLength);
218
219 if(CurrentTest == 0)
220 ok(1, "\n"); /*checks that QueryRoutine is called*/
221 if(CurrentTest > 7)
222 ok(!1, "Invalid Test Specified!\n");
223
224 CurrentTest++;
225
226 if(ValName)
227 pRtlFreeHeap(GetProcessHeap(), 0, ValName);
228
229 if(ValData)
230 pRtlFreeHeap(GetProcessHeap(), 0, ValData);
231
232 return ret;
233 }
234
235 static void test_RtlQueryRegistryValues(void)
236 {
237
238 /*
239 ******************************
240 * QueryTable Flags *
241 ******************************
242 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
243 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
244 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
245 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
246 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
247 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
248 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
249 ******************************
250
251
252 **Test layout(numbered according to CurrentTest value)**
253 0)NOVALUE Just make sure call-back works
254 1)Null Name See if QueryRoutine is called for every value in current key
255 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
256 3)REQUIRED Test for value that's not there
257 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
258 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
259 6)DefaultType Test return values when key isn't present
260 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
261 8)DefaultLength Test Default Length with DefaultType = REG_SZ
262 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
263 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
264 11)DefaultData Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be)
265 12)Delete Try to delete value key
266
267 */
268 NTSTATUS status;
269 ULONG RelativeTo;
270
271 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
272 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
273
274 QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
275
276 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
277
278 QueryTable[0].QueryRoutine = QueryRoutine;
279 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
280 QueryTable[0].Name = NULL;
281 QueryTable[0].EntryContext = NULL;
282 QueryTable[0].DefaultType = REG_BINARY;
283 QueryTable[0].DefaultData = NULL;
284 QueryTable[0].DefaultLength = 100;
285
286 QueryTable[1].QueryRoutine = QueryRoutine;
287 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DELETE;
288 QueryTable[1].Name = L"multisztest";
289 QueryTable[1].EntryContext = 0;
290 QueryTable[1].DefaultType = REG_NONE;
291 QueryTable[1].DefaultData = NULL;
292 QueryTable[1].DefaultLength = 0;
293
294 QueryTable[2].QueryRoutine = QueryRoutine;
295 QueryTable[2].Flags = 0;
296 QueryTable[2].Name = NULL;
297 QueryTable[2].EntryContext = 0;
298 QueryTable[2].DefaultType = REG_NONE;
299 QueryTable[2].DefaultData = NULL;
300 QueryTable[2].DefaultLength = 0;
301
302 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
303 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08lx\n", status);
304
305 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
306 }
307
308 static void test_NtCreateKey(void)
309 {
310 /*Create WineTest*/
311 OBJECT_ATTRIBUTES attr;
312 HANDLE key;
313 ACCESS_MASK am = GENERIC_ALL;
314 NTSTATUS status;
315
316 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
317 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
318 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\n", status);
319
320 pNtClose(key);
321 }
322
323 static void test_NtSetValueKey(void)
324 {
325 HANDLE key;
326 NTSTATUS status;
327 OBJECT_ATTRIBUTES attr;
328 ACCESS_MASK am = KEY_WRITE;
329 UNICODE_STRING ValName;
330 UNICODE_STRING ValNameMultiSz;
331 DWORD data = 711;
332 static const WCHAR DataMultiSz[] = {'T','e','s','t','V','a','l','u','e','1',0,
333 'T','e','s','t','V','a','l','u','e','2',0,
334 'T','e','s','t','V','a','l','u','e','3',0,0,
335 'T','e','s','t','V','a','l','u','e','5',0,0,0};
336
337 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
338 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
339 status = pNtOpenKey(&key, am, &attr);
340 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
341
342 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
343 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status);
344
345 pRtlFreeUnicodeString(&ValName);
346
347 pRtlCreateUnicodeStringFromAsciiz(&ValNameMultiSz, "multisztest");
348
349 status = pNtSetValueKey(key, &ValNameMultiSz, 0, REG_MULTI_SZ, (PVOID)DataMultiSz, sizeof(DataMultiSz));
350 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status);
351
352 pRtlFreeUnicodeString(&ValNameMultiSz);
353
354 pNtClose(key);
355 }
356
357 static void test_RtlOpenCurrentUser(void)
358 {
359 NTSTATUS status;
360 HANDLE handle;
361 status=pRtlOpenCurrentUser(KEY_READ, &handle);
362 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08lx\n", status);
363 pNtClose(handle);
364 }
365
366 static void test_RtlCheckRegistryKey(void)
367 {
368 NTSTATUS status;
369
370 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
371 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\n", status);
372
373 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
374 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08lx\n", status);
375 }
376
377 static void test_RtlQueryRegistryDelete(void)
378 {
379 HANDLE key;
380 NTSTATUS status;
381 OBJECT_ATTRIBUTES attr;
382 UNICODE_STRING ValNameMultiSz;
383 WCHAR sBuf[255];
384 DWORD ValueSize;
385
386 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
387 status = pNtOpenKey(&key, KEY_READ, &attr);
388 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
389
390 pRtlCreateUnicodeStringFromAsciiz(&ValNameMultiSz, "multisztest");
391
392 status = pNtQueryValueKey(key, &ValNameMultiSz, 0, (void*)sBuf, sizeof(sBuf), &ValueSize);
393 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey returns: 0x%08lx instead of STATUS_OBJECT_NAME_NOT_FOUND\n", status);
394
395 pRtlFreeUnicodeString(&ValNameMultiSz);
396
397 pNtClose(key);
398 }
399
400 static void test_NtDeleteKey(void)
401 {
402 NTSTATUS status;
403 HANDLE hkey;
404 OBJECT_ATTRIBUTES attr;
405 ACCESS_MASK am = KEY_ALL_ACCESS;
406
407 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
408 status = pNtOpenKey(&hkey, am, &attr);
409
410 status = pNtDeleteKey(hkey);
411 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
412
413 pNtClose(hkey);
414 }
415
416 START_TEST(reg)
417 {
418 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0};
419 if(!InitFunctionPtrs())
420 return;
421 pRtlFormatCurrentUserKeyPath(&winetestpath);
422 winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
423 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
424 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
425
426 pRtlAppendUnicodeToString(&winetestpath, winetest);
427
428 test_NtCreateKey();
429 test_NtSetValueKey();
430 test_RtlCheckRegistryKey();
431 test_RtlOpenCurrentUser();
432 test_RtlQueryRegistryValues();
433 test_RtlQueryRegistryDelete();
434 test_NtDeleteKey();
435
436 pRtlFreeUnicodeString(&winetestpath);
437
438 FreeLibrary(hntdll);
439 }