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