push 87b6981010d7405c33b14cddcceec21b47729eba
[wine/hacks.git] / dlls / ntdll / tests / reg.c
bloba4802c825d2179e6bc4859b596945f450ba0fd2a
1 /* Unit test suite for Rtl* Registry API functions
3 * Copyright 2003 Thomas Mertes
4 * Copyright 2005 Brad DeMorrow
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.
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.
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
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
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"
32 /* A test string */
33 static const WCHAR stringW[] = {'s', 't', 'r', 'i', 'n', 'g', 'W', 0};
34 /* A size, in bytes, short enough to cause truncation of the above */
35 #define STR_TRUNC_SIZE (sizeof(stringW)-2*sizeof(*stringW))
37 #ifndef __WINE_WINTERNL_H
39 /* RtlQueryRegistryValues structs and defines */
40 #define RTL_REGISTRY_ABSOLUTE 0
41 #define RTL_REGISTRY_SERVICES 1
42 #define RTL_REGISTRY_CONTROL 2
43 #define RTL_REGISTRY_WINDOWS_NT 3
44 #define RTL_REGISTRY_DEVICEMAP 4
45 #define RTL_REGISTRY_USER 5
47 #define RTL_REGISTRY_HANDLE 0x40000000
48 #define RTL_REGISTRY_OPTIONAL 0x80000000
50 #define RTL_QUERY_REGISTRY_SUBKEY 0x00000001
51 #define RTL_QUERY_REGISTRY_TOPKEY 0x00000002
52 #define RTL_QUERY_REGISTRY_REQUIRED 0x00000004
53 #define RTL_QUERY_REGISTRY_NOVALUE 0x00000008
54 #define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010
55 #define RTL_QUERY_REGISTRY_DIRECT 0x00000020
56 #define RTL_QUERY_REGISTRY_DELETE 0x00000040
58 typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR ValueName,
59 ULONG ValueType,
60 PVOID ValueData,
61 ULONG ValueLength,
62 PVOID Context,
63 PVOID EntryContext);
65 typedef struct _RTL_QUERY_REGISTRY_TABLE {
66 PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
67 ULONG Flags;
68 PWSTR Name;
69 PVOID EntryContext;
70 ULONG DefaultType;
71 PVOID DefaultData;
72 ULONG DefaultLength;
73 } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;
75 typedef struct _KEY_VALUE_BASIC_INFORMATION {
76 ULONG TitleIndex;
77 ULONG Type;
78 ULONG NameLength;
79 WCHAR Name[1];
80 } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION;
82 typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
83 ULONG TitleIndex;
84 ULONG Type;
85 ULONG DataLength;
86 UCHAR Data[1];
87 } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
89 typedef struct _KEY_VALUE_FULL_INFORMATION {
90 ULONG TitleIndex;
91 ULONG Type;
92 ULONG DataOffset;
93 ULONG DataLength;
94 ULONG NameLength;
95 WCHAR Name[1];
96 } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
98 typedef enum _KEY_VALUE_INFORMATION_CLASS {
99 KeyValueBasicInformation,
100 KeyValueFullInformation,
101 KeyValuePartialInformation,
102 KeyValueFullInformationAlign64,
103 KeyValuePartialInformationAlign64
104 } KEY_VALUE_INFORMATION_CLASS;
106 #define InitializeObjectAttributes(p,n,a,r,s) \
107 do { \
108 (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
109 (p)->RootDirectory = r; \
110 (p)->Attributes = a; \
111 (p)->ObjectName = n; \
112 (p)->SecurityDescriptor = s; \
113 (p)->SecurityQualityOfService = NULL; \
114 } while (0)
116 #endif
118 static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
119 static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
120 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
121 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
122 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
123 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
124 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE);
125 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
126 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
127 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
128 static NTSTATUS (WINAPI * pNtFlushKey)(HANDLE);
129 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
130 static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
131 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
132 PULONG dispos );
133 static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
134 static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
135 ULONG, const void*, ULONG );
136 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
137 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
138 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
139 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
140 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
141 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
142 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
143 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
144 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
146 static HMODULE hntdll = 0;
147 static int CurrentTest = 0;
148 static UNICODE_STRING winetestpath;
150 #define NTDLL_GET_PROC(func) \
151 p ## func = (void*)GetProcAddress(hntdll, #func); \
152 if(!p ## func) { \
153 trace("GetProcAddress(%s) failed\n", #func); \
154 FreeLibrary(hntdll); \
155 return FALSE; \
158 static BOOL InitFunctionPtrs(void)
160 hntdll = LoadLibraryA("ntdll.dll");
161 if(!hntdll) {
162 trace("Could not load ntdll.dll\n");
163 return FALSE;
165 NTDLL_GET_PROC(RtlInitUnicodeString)
166 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
167 NTDLL_GET_PROC(RtlCreateUnicodeString)
168 NTDLL_GET_PROC(RtlFreeUnicodeString)
169 NTDLL_GET_PROC(NtDeleteValueKey)
170 NTDLL_GET_PROC(RtlQueryRegistryValues)
171 NTDLL_GET_PROC(RtlCheckRegistryKey)
172 NTDLL_GET_PROC(RtlOpenCurrentUser)
173 NTDLL_GET_PROC(NtClose)
174 NTDLL_GET_PROC(NtDeleteValueKey)
175 NTDLL_GET_PROC(NtCreateKey)
176 NTDLL_GET_PROC(NtFlushKey)
177 NTDLL_GET_PROC(NtDeleteKey)
178 NTDLL_GET_PROC(NtQueryValueKey)
179 NTDLL_GET_PROC(NtSetValueKey)
180 NTDLL_GET_PROC(NtOpenKey)
181 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
182 NTDLL_GET_PROC(RtlReAllocateHeap)
183 NTDLL_GET_PROC(RtlAppendUnicodeToString)
184 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
185 NTDLL_GET_PROC(RtlFreeHeap)
186 NTDLL_GET_PROC(RtlAllocateHeap)
187 NTDLL_GET_PROC(RtlZeroMemory)
188 NTDLL_GET_PROC(RtlpNtQueryValueKey)
189 return TRUE;
191 #undef NTDLL_GET_PROC
193 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
194 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
196 NTSTATUS ret = STATUS_SUCCESS;
197 int ValueNameLength = 0;
198 LPSTR ValName = 0;
199 trace("**Test %d**\n", CurrentTest);
201 if(ValueName)
203 ValueNameLength = lstrlenW(ValueName);
205 ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
207 WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
209 trace("ValueName: %s\n", ValName);
211 else
212 trace("ValueName: (null)\n");
214 switch(ValueType)
216 case REG_NONE:
217 trace("ValueType: REG_NONE\n");
218 trace("ValueData: %p\n", ValueData);
219 break;
221 case REG_BINARY:
222 trace("ValueType: REG_BINARY\n");
223 trace("ValueData: %p\n", ValueData);
224 break;
226 case REG_SZ:
227 trace("ValueType: REG_SZ\n");
228 trace("ValueData: %s\n", (char*)ValueData);
229 break;
231 case REG_MULTI_SZ:
232 trace("ValueType: REG_MULTI_SZ\n");
233 trace("ValueData: %s\n", (char*)ValueData);
234 break;
236 case REG_EXPAND_SZ:
237 trace("ValueType: REG_EXPAND_SZ\n");
238 trace("ValueData: %s\n", (char*)ValueData);
239 break;
241 case REG_DWORD:
242 trace("ValueType: REG_DWORD\n");
243 trace("ValueData: %p\n", ValueData);
244 break;
246 trace("ValueLength: %d\n", (int)ValueLength);
248 if(CurrentTest == 0)
249 ok(1, "\n"); /*checks that QueryRoutine is called*/
250 if(CurrentTest > 7)
251 ok(!1, "Invalid Test Specified!\n");
253 CurrentTest++;
255 if(ValName)
256 pRtlFreeHeap(GetProcessHeap(), 0, ValName);
258 return ret;
261 static void test_RtlQueryRegistryValues(void)
265 ******************************
266 * QueryTable Flags *
267 ******************************
268 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
269 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
270 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
271 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
272 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
273 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
274 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
275 ******************************
278 **Test layout(numbered according to CurrentTest value)**
279 0)NOVALUE Just make sure call-back works
280 1)Null Name See if QueryRoutine is called for every value in current key
281 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
282 3)REQUIRED Test for value that's not there
283 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
284 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
285 6)DefaultType Test return values when key isn't present
286 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
287 8)DefaultLength Test Default Length with DefaultType = REG_SZ
288 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
289 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
290 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
291 12)Delete Try to delete value key
294 NTSTATUS status;
295 ULONG RelativeTo;
297 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
298 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
300 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
302 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
304 QueryTable[0].QueryRoutine = QueryRoutine;
305 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
306 QueryTable[0].Name = NULL;
307 QueryTable[0].EntryContext = NULL;
308 QueryTable[0].DefaultType = REG_BINARY;
309 QueryTable[0].DefaultData = NULL;
310 QueryTable[0].DefaultLength = 100;
312 QueryTable[1].QueryRoutine = QueryRoutine;
313 QueryTable[1].Flags = 0;
314 QueryTable[1].Name = NULL;
315 QueryTable[1].EntryContext = 0;
316 QueryTable[1].DefaultType = REG_NONE;
317 QueryTable[1].DefaultData = NULL;
318 QueryTable[1].DefaultLength = 0;
320 QueryTable[2].QueryRoutine = NULL;
321 QueryTable[2].Flags = 0;
322 QueryTable[2].Name = NULL;
323 QueryTable[2].EntryContext = 0;
324 QueryTable[2].DefaultType = REG_NONE;
325 QueryTable[2].DefaultData = NULL;
326 QueryTable[2].DefaultLength = 0;
328 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
329 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
331 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
334 static void test_NtOpenKey(void)
336 HANDLE key;
337 NTSTATUS status;
338 OBJECT_ATTRIBUTES attr;
339 ACCESS_MASK am = KEY_READ;
341 /* All NULL */
342 status = pNtOpenKey(NULL, 0, NULL);
343 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
345 /* NULL attributes */
346 status = pNtOpenKey(&key, 0, NULL);
347 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
348 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
350 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
352 /* NULL key */
353 status = pNtOpenKey(NULL, 0, &attr);
354 todo_wine
355 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
357 /* Length > sizeof(OBJECT_ATTRIBUTES) */
358 attr.Length *= 2;
359 status = pNtOpenKey(&key, am, &attr);
360 todo_wine
361 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
364 static void test_NtCreateKey(void)
366 /*Create WineTest*/
367 OBJECT_ATTRIBUTES attr;
368 HANDLE key;
369 ACCESS_MASK am = GENERIC_ALL;
370 NTSTATUS status;
372 /* All NULL */
373 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
374 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
375 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
377 /* Only the key */
378 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
379 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
380 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
382 /* Only accessmask */
383 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
384 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
385 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
387 /* Key and accessmask */
388 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
389 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
390 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
392 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
394 /* Only attributes */
395 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
396 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
398 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
399 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
401 /* Length > sizeof(OBJECT_ATTRIBUTES) */
402 attr.Length *= 2;
403 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
404 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
406 pNtClose(key);
409 static void test_NtSetValueKey(void)
411 HANDLE key;
412 NTSTATUS status;
413 OBJECT_ATTRIBUTES attr;
414 ACCESS_MASK am = KEY_WRITE;
415 UNICODE_STRING ValName;
416 DWORD data = 711;
418 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
419 status = pNtOpenKey(&key, am, &attr);
420 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
422 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
423 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
424 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
425 pRtlFreeUnicodeString(&ValName);
427 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
428 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
429 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
430 pRtlFreeUnicodeString(&ValName);
432 pNtClose(key);
435 static void test_RtlOpenCurrentUser(void)
437 NTSTATUS status;
438 HANDLE handle;
439 status=pRtlOpenCurrentUser(KEY_READ, &handle);
440 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
441 pNtClose(handle);
444 static void test_RtlCheckRegistryKey(void)
446 NTSTATUS status;
448 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
449 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
451 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
452 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
455 static void test_NtFlushKey(void)
457 NTSTATUS status;
458 HANDLE hkey;
459 OBJECT_ATTRIBUTES attr;
460 ACCESS_MASK am = KEY_ALL_ACCESS;
462 status = pNtFlushKey(NULL);
463 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
465 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
466 pNtOpenKey(&hkey, am, &attr);
468 status = pNtFlushKey(hkey);
469 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
471 pNtClose(hkey);
474 static void test_NtQueryValueKey(void)
476 HANDLE key;
477 NTSTATUS status;
478 OBJECT_ATTRIBUTES attr;
479 UNICODE_STRING ValName;
480 KEY_VALUE_BASIC_INFORMATION *basic_info;
481 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
482 KEY_VALUE_FULL_INFORMATION *full_info;
483 DWORD len;
485 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
487 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
488 status = pNtOpenKey(&key, KEY_READ, &attr);
489 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
491 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
492 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
493 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
494 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
495 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
496 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
497 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
498 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
500 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
501 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
502 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
503 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
504 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
505 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
506 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
507 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
508 HeapFree(GetProcessHeap(), 0, basic_info);
510 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
511 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
512 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
513 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
514 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
515 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
516 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
517 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
519 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
520 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
521 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
522 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
523 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
524 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
525 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
526 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
527 HeapFree(GetProcessHeap(), 0, partial_info);
529 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
530 full_info = HeapAlloc(GetProcessHeap(), 0, len);
531 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
532 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
533 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
534 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
535 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
536 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
537 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
538 "NtQueryValueKey returned wrong len %d\n", len);
539 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
541 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
542 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
543 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
544 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
545 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
546 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
547 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
548 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
549 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
550 *(DWORD *)((char *)full_info + full_info->DataOffset));
551 HeapFree(GetProcessHeap(), 0, full_info);
553 pRtlFreeUnicodeString(&ValName);
554 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
556 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
557 todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
558 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
559 memset(partial_info, 0xbd, len+1);
560 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
561 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
562 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
563 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
564 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
565 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
566 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
567 HeapFree(GetProcessHeap(), 0, partial_info);
569 pRtlFreeUnicodeString(&ValName);
570 pNtClose(key);
573 static void test_NtDeleteKey(void)
575 NTSTATUS status;
576 HANDLE hkey;
577 OBJECT_ATTRIBUTES attr;
578 ACCESS_MASK am = KEY_ALL_ACCESS;
580 status = pNtDeleteKey(NULL);
581 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
583 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
584 status = pNtOpenKey(&hkey, am, &attr);
586 status = pNtDeleteKey(hkey);
587 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
590 static void test_RtlpNtQueryValueKey(void)
592 NTSTATUS status;
594 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
595 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
598 static void test_symlinks(void)
600 static const WCHAR linkW[] = {'l','i','n','k',0};
601 static const WCHAR valueW[] = {'v','a','l','u','e',0};
602 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
603 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
604 char buffer[1024];
605 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
606 WCHAR *target;
607 UNICODE_STRING symlink_str, link_str, target_str, value_str;
608 HANDLE root, key, link;
609 OBJECT_ATTRIBUTES attr;
610 NTSTATUS status;
611 DWORD target_len, len, dw;
613 pRtlInitUnicodeString( &link_str, linkW );
614 pRtlInitUnicodeString( &symlink_str, symlinkW );
615 pRtlInitUnicodeString( &target_str, targetW + 1 );
616 pRtlInitUnicodeString( &value_str, valueW );
618 target_len = winetestpath.Length + sizeof(targetW);
619 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len );
620 memcpy( target, winetestpath.Buffer, winetestpath.Length );
621 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
623 attr.Length = sizeof(attr);
624 attr.RootDirectory = 0;
625 attr.Attributes = 0;
626 attr.ObjectName = &winetestpath;
627 attr.SecurityDescriptor = NULL;
628 attr.SecurityQualityOfService = NULL;
630 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
631 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
633 attr.RootDirectory = root;
634 attr.ObjectName = &link_str;
635 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
636 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
638 /* REG_SZ is not allowed */
639 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
640 todo_wine
641 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
642 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
643 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
644 /* other values are not allowed */
645 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
646 todo_wine
647 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
649 /* try opening the target through the link */
651 attr.ObjectName = &link_str;
652 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
653 todo_wine
654 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
655 if (!status) pNtClose( key );
657 attr.ObjectName = &target_str;
658 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
659 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
661 dw = 0xbeef;
662 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
663 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
664 pNtClose( key );
666 attr.ObjectName = &link_str;
667 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
668 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
670 len = sizeof(buffer);
671 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
672 todo_wine
674 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
675 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
678 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
679 todo_wine
680 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
682 /* REG_LINK can be created in non-link keys */
683 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
684 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
685 len = sizeof(buffer);
686 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
687 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
688 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
689 "wrong len %u\n", len );
690 status = pNtDeleteValueKey( key, &symlink_str );
691 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
693 pNtClose( key );
695 /* now open the symlink itself */
697 attr.RootDirectory = root;
698 attr.Attributes = OBJ_OPENLINK;
699 attr.ObjectName = &link_str;
700 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
701 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
703 len = sizeof(buffer);
704 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
705 todo_wine
707 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
708 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
709 "wrong len %u\n", len );
711 pNtClose( key );
713 /* target with terminating null doesn't work */
714 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
715 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
716 attr.Attributes = 0;
717 attr.ObjectName = &link_str;
718 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
719 todo_wine
720 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
721 if (!status) pNtClose( key );
723 /* relative symlink, works only on win2k */
724 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
725 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
726 attr.ObjectName = &link_str;
727 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
728 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
729 "NtOpenKey wrong status 0x%08x\n", status );
730 if (!status) pNtClose( key );
732 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
733 todo_wine
734 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
735 if (!status) pNtClose( key );
737 status = pNtDeleteKey( link );
738 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
739 pNtClose( link );
741 attr.ObjectName = &target_str;
742 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
743 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
744 status = pNtDeleteKey( key );
745 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
746 pNtClose( key );
748 status = pNtDeleteKey( root );
749 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
750 pNtClose( root );
753 START_TEST(reg)
755 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
756 if(!InitFunctionPtrs())
757 return;
758 pRtlFormatCurrentUserKeyPath(&winetestpath);
759 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
760 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
761 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
763 pRtlAppendUnicodeToString(&winetestpath, winetest);
765 test_NtCreateKey();
766 test_NtOpenKey();
767 test_NtSetValueKey();
768 test_RtlCheckRegistryKey();
769 test_RtlOpenCurrentUser();
770 test_RtlQueryRegistryValues();
771 test_RtlpNtQueryValueKey();
772 test_NtFlushKey();
773 test_NtQueryValueKey();
774 test_NtDeleteKey();
775 test_symlinks();
777 pRtlFreeUnicodeString(&winetestpath);
779 FreeLibrary(hntdll);