msi: Write-strings warnings fix.
[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 #define InitializeObjectAttributes(p,n,a,r,s) \
71     do { \
72         (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
73         (p)->RootDirectory = r; \
74         (p)->Attributes = a; \
75         (p)->ObjectName = n; \
76         (p)->SecurityDescriptor = s; \
77         (p)->SecurityQualityOfService = NULL; \
78     } while (0)
79
80 #endif
81
82 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
83 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
84 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
85 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
86 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
87 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, OUT PHKEY);
88 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
89 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
90 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
91 static NTSTATUS (WINAPI * pNtFlushKey)(HKEY);
92 static NTSTATUS (WINAPI * pNtDeleteKey)(HKEY);
93 static NTSTATUS (WINAPI * pNtCreateKey)( PHKEY 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)( PHKEY, const PUNICODE_STRING, ULONG,
97                                ULONG, const PVOID, ULONG  );
98 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
99 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
100 static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
101 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
102 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
103 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
104 static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
105 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
106
107 static HMODULE hntdll = 0;
108 static int CurrentTest = 0;
109 static UNICODE_STRING winetestpath;
110
111 #define NTDLL_GET_PROC(func) \
112     p ## func = (void*)GetProcAddress(hntdll, #func); \
113     if(!p ## func) { \
114         trace("GetProcAddress(%s) failed\n", #func); \
115         FreeLibrary(hntdll); \
116         return FALSE; \
117     }
118
119 static BOOL InitFunctionPtrs(void)
120 {
121     hntdll = LoadLibraryA("ntdll.dll");
122     if(!hntdll) {
123         trace("Could not load ntdll.dll\n");
124         return FALSE;
125     }
126     if (hntdll)
127     {
128         NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
129         NTDLL_GET_PROC(RtlCreateUnicodeString)
130         NTDLL_GET_PROC(RtlFreeUnicodeString)
131         NTDLL_GET_PROC(NtDeleteValueKey)
132         NTDLL_GET_PROC(RtlQueryRegistryValues)
133         NTDLL_GET_PROC(RtlCheckRegistryKey)
134         NTDLL_GET_PROC(RtlOpenCurrentUser)
135         NTDLL_GET_PROC(NtClose)
136         NTDLL_GET_PROC(NtDeleteValueKey)
137         NTDLL_GET_PROC(NtCreateKey)
138         NTDLL_GET_PROC(NtFlushKey)
139         NTDLL_GET_PROC(NtDeleteKey)
140         NTDLL_GET_PROC(NtSetValueKey)
141         NTDLL_GET_PROC(NtOpenKey)
142         NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
143         NTDLL_GET_PROC(RtlReAllocateHeap)
144         NTDLL_GET_PROC(RtlAppendUnicodeToString)
145         NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
146         NTDLL_GET_PROC(RtlFreeHeap)
147         NTDLL_GET_PROC(RtlAllocateHeap)
148         NTDLL_GET_PROC(RtlZeroMemory)
149     }
150     return TRUE;
151 }
152 #undef NTDLL_GET_PROC
153
154 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
155                               IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
156 {
157     NTSTATUS ret = STATUS_SUCCESS;
158     int ValueNameLength = 0;
159     LPSTR ValName = 0;
160     trace("**Test %d**\n", CurrentTest);
161
162     if(ValueName)
163     {
164         ValueNameLength = lstrlenW(ValueName);
165
166         ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
167
168         WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
169
170         trace("ValueName: %s\n", ValName);
171     }
172     else
173         trace("ValueName: (null)\n");
174
175     switch(ValueType)
176     {
177             case REG_NONE:
178                 trace("ValueType: REG_NONE\n");
179                 trace("ValueData: %d\n", (int)ValueData);
180                 break;
181
182             case REG_BINARY:
183                 trace("ValueType: REG_BINARY\n");
184                 trace("ValueData: %d\n", (int)ValueData);
185                 break;
186
187             case REG_SZ:
188                 trace("ValueType: REG_SZ\n");
189                 trace("ValueData: %s\n", (char*)ValueData);
190                 break;
191
192             case REG_MULTI_SZ:
193                 trace("ValueType: REG_MULTI_SZ\n");
194                 trace("ValueData: %s\n", (char*)ValueData);
195                 break;
196
197             case REG_EXPAND_SZ:
198                 trace("ValueType: REG_EXPAND_SZ\n");
199                 trace("ValueData: %s\n", (char*)ValueData);
200                 break;
201
202             case REG_DWORD:
203                 trace("ValueType: REG_DWORD\n");
204                 trace("ValueData: %d\n", (int)ValueData);
205                 break;
206     };
207     trace("ValueLength: %d\n", (int)ValueLength);
208
209     if(CurrentTest == 0)
210         ok(1, "\n"); /*checks that QueryRoutine is called*/
211     if(CurrentTest > 7)
212         ok(!1, "Invalid Test Specified!\n");
213
214     CurrentTest++;
215
216     if(ValName)
217         pRtlFreeHeap(GetProcessHeap(), 0, ValName);
218
219     return ret;
220 }
221
222 static void test_RtlQueryRegistryValues(void)
223 {
224
225     /*
226     ******************************
227     *       QueryTable Flags     *
228     ******************************
229     *RTL_QUERY_REGISTRY_SUBKEY   * Name is the name of a subkey relative to Path
230     *RTL_QUERY_REGISTRY_TOPKEY   * Resets location to original RelativeTo and Path
231     *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
232     *RTL_QUERY_REGISTRY_NOVALUE  * We just want a call-back
233     *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
234     *RTL_QUERY_REGISTRY_DIRECT   * Results of query will be stored in EntryContext(QueryRoutine ignored)
235     *RTL_QUERY_REGISTRY_DELETE   * Delete value key after query
236     ******************************
237
238
239     **Test layout(numbered according to CurrentTest value)**
240     0)NOVALUE           Just make sure call-back works
241     1)Null Name         See if QueryRoutine is called for every value in current key
242     2)SUBKEY            See if we can use SUBKEY to change the current path on the fly
243     3)REQUIRED          Test for value that's not there
244     4)NOEXPAND          See if it will return multiple strings(no expand should split strings up)
245     5)DIRECT            Make it store data directly in EntryContext and not call QueryRoutine
246     6)DefaultType       Test return values when key isn't present
247     7)DefaultValue      Test Default Value returned with key isn't present(and no REQUIRED flag set)
248     8)DefaultLength     Test Default Length with DefaultType = REG_SZ
249    9)DefaultLength      Test Default Length with DefaultType = REG_MULTI_SZ
250    10)DefaultLength     Test Default Length with DefaultType = REG_EXPAND_SZ
251    11)DefaultData       Test whether DefaultData is used while DefaltType = REG_NONE(shouldn't be)
252    12)Delete            Try to delete value key
253
254     */
255     NTSTATUS status;
256     ULONG RelativeTo;
257
258     PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
259     RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
260
261     QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
262
263     pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
264
265     QueryTable[0].QueryRoutine = QueryRoutine;
266     QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
267     QueryTable[0].Name = NULL;
268     QueryTable[0].EntryContext = NULL;
269     QueryTable[0].DefaultType = REG_BINARY;
270     QueryTable[0].DefaultData = NULL;
271     QueryTable[0].DefaultLength = 100;
272
273     QueryTable[1].QueryRoutine = QueryRoutine;
274     QueryTable[1].Flags = 0;
275     QueryTable[1].Name = NULL;
276     QueryTable[1].EntryContext = 0;
277     QueryTable[1].DefaultType = REG_NONE;
278     QueryTable[1].DefaultData = NULL;
279     QueryTable[1].DefaultLength = 0;
280
281     QueryTable[2].QueryRoutine = NULL;
282     QueryTable[2].Flags = 0;
283     QueryTable[2].Name = NULL;
284     QueryTable[2].EntryContext = 0;
285     QueryTable[2].DefaultType = REG_NONE;
286     QueryTable[2].DefaultData = NULL;
287     QueryTable[2].DefaultLength = 0;
288
289     status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
290     ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08lx\n", status);
291
292     pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
293 }
294
295 static void test_NtOpenKey(void)
296 {
297     HANDLE key;
298     NTSTATUS status;
299     OBJECT_ATTRIBUTES attr;
300     ACCESS_MASK am = KEY_READ;
301
302 #if 0 /* Crashes Wine */
303     /* All NULL */
304     status = pNtOpenKey(NULL, 0, NULL);
305     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
306
307     /* NULL attributes */
308     status = pNtOpenKey(&key, 0, NULL);
309     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
310         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08lx\n", status);
311 #endif 
312
313     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
314
315     /* NULL key */
316     status = pNtOpenKey(NULL, 0, &attr);
317     todo_wine
318         ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
319
320     /* Length > sizeof(OBJECT_ATTRIBUTES) */
321     attr.Length *= 2;
322     status = pNtOpenKey(&key, am, &attr);
323     todo_wine
324         ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08lx\n", status);
325 }
326
327 static void test_NtCreateKey(void)
328 {
329     /*Create WineTest*/
330     OBJECT_ATTRIBUTES attr;
331     HKEY key;
332     ACCESS_MASK am = GENERIC_ALL;
333     NTSTATUS status;
334
335     /* All NULL */
336     status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
337     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
338
339     /* Only the key */
340     status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
341     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
342         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08lx\n", status);
343
344     /* Only accessmask */
345     status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
346     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
347
348     /* Key and accessmask */
349     status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
350     ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
351         "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08lx\n", status);
352
353     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
354
355     /* Only attributes */
356     status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
357     ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08lx\n", status);
358
359     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
360     ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\n", status);
361
362     /* Length > sizeof(OBJECT_ATTRIBUTES) */
363     attr.Length *= 2;
364     status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
365     ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08lx\n", status);
366
367     pNtClose(&key);
368 }
369
370 static void test_NtSetValueKey(void)
371 {
372     HANDLE key;
373     NTSTATUS status;
374     OBJECT_ATTRIBUTES attr;
375     ACCESS_MASK am = KEY_WRITE;
376     UNICODE_STRING ValName;
377     DWORD data = 711;
378
379     pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
380
381     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
382     status = pNtOpenKey(&key, am, &attr);
383     ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
384
385     status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
386     ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\n", status);
387
388     pRtlFreeUnicodeString(&ValName);
389     pNtClose(&key);
390 }
391
392 static void test_RtlOpenCurrentUser(void)
393 {
394     NTSTATUS status;
395     HKEY handle;
396     status=pRtlOpenCurrentUser(KEY_READ, &handle);
397     ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08lx\n", status);
398     pNtClose(&handle);
399 }
400
401 static void test_RtlCheckRegistryKey(void)
402 {
403     NTSTATUS status;
404
405     status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
406     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\n", status);
407
408     status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
409     ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08lx\n", status);
410 }
411
412 static void test_NtFlushKey(void)
413 {
414     NTSTATUS status;
415     HANDLE hkey;
416     OBJECT_ATTRIBUTES attr;
417     ACCESS_MASK am = KEY_ALL_ACCESS;
418
419     status = pNtFlushKey(NULL);
420     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08lx\n", status);
421
422     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
423     pNtOpenKey(&hkey, am, &attr);
424
425     status = pNtFlushKey(hkey);
426     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
427
428     pNtClose(hkey);
429 }
430
431 static void test_NtDeleteKey(void)
432 {
433     NTSTATUS status;
434     HANDLE hkey;
435     OBJECT_ATTRIBUTES attr;
436     ACCESS_MASK am = KEY_ALL_ACCESS;
437
438     status = pNtDeleteKey(NULL);
439     ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08lx\n", status);
440
441     InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
442     status = pNtOpenKey(&hkey, am, &attr);
443
444     status = pNtDeleteKey(hkey);
445     ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
446 }
447
448 START_TEST(reg)
449 {
450     static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0};
451     if(!InitFunctionPtrs())
452         return;
453     pRtlFormatCurrentUserKeyPath(&winetestpath);
454     winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
455                            winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
456     winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
457
458     pRtlAppendUnicodeToString(&winetestpath, winetest);
459
460     test_NtOpenKey();
461     test_NtCreateKey();
462     test_NtSetValueKey();
463     test_RtlCheckRegistryKey();
464     test_RtlOpenCurrentUser();
465     test_RtlQueryRegistryValues();
466     test_NtFlushKey();
467     test_NtDeleteKey();
468
469     pRtlFreeUnicodeString(&winetestpath);
470
471     FreeLibrary(hntdll);
472 }