ntdll/tests: Add some test cases for Wow64 registry redirection.
[wine/hacks.git] / dlls / ntdll / tests / reg.c
blob79e5ecea061ad2b04092f62933dfb864fe4917cb
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 * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
137 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
138 static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR);
139 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
140 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
141 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
142 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
143 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
144 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
145 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
146 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(ACCESS_MASK,HANDLE*);
148 static HMODULE hntdll = 0;
149 static int CurrentTest = 0;
150 static UNICODE_STRING winetestpath;
152 #define NTDLL_GET_PROC(func) \
153 p ## func = (void*)GetProcAddress(hntdll, #func); \
154 if(!p ## func) { \
155 trace("GetProcAddress(%s) failed\n", #func); \
156 FreeLibrary(hntdll); \
157 return FALSE; \
160 static BOOL InitFunctionPtrs(void)
162 hntdll = LoadLibraryA("ntdll.dll");
163 if(!hntdll) {
164 trace("Could not load ntdll.dll\n");
165 return FALSE;
167 NTDLL_GET_PROC(RtlInitUnicodeString)
168 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
169 NTDLL_GET_PROC(RtlCreateUnicodeString)
170 NTDLL_GET_PROC(RtlFreeUnicodeString)
171 NTDLL_GET_PROC(NtDeleteValueKey)
172 NTDLL_GET_PROC(RtlQueryRegistryValues)
173 NTDLL_GET_PROC(RtlCheckRegistryKey)
174 NTDLL_GET_PROC(RtlOpenCurrentUser)
175 NTDLL_GET_PROC(NtClose)
176 NTDLL_GET_PROC(NtDeleteValueKey)
177 NTDLL_GET_PROC(NtCreateKey)
178 NTDLL_GET_PROC(NtFlushKey)
179 NTDLL_GET_PROC(NtDeleteKey)
180 NTDLL_GET_PROC(NtQueryValueKey)
181 NTDLL_GET_PROC(NtQueryInformationProcess)
182 NTDLL_GET_PROC(NtSetValueKey)
183 NTDLL_GET_PROC(NtOpenKey)
184 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
185 NTDLL_GET_PROC(RtlReAllocateHeap)
186 NTDLL_GET_PROC(RtlAppendUnicodeToString)
187 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
188 NTDLL_GET_PROC(RtlFreeHeap)
189 NTDLL_GET_PROC(RtlAllocateHeap)
190 NTDLL_GET_PROC(RtlZeroMemory)
191 NTDLL_GET_PROC(RtlpNtQueryValueKey)
192 NTDLL_GET_PROC(RtlOpenCurrentUser)
193 return TRUE;
195 #undef NTDLL_GET_PROC
197 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
198 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
200 NTSTATUS ret = STATUS_SUCCESS;
201 int ValueNameLength = 0;
202 LPSTR ValName = 0;
203 trace("**Test %d**\n", CurrentTest);
205 if(ValueName)
207 ValueNameLength = lstrlenW(ValueName);
209 ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength);
211 WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0);
213 trace("ValueName: %s\n", ValName);
215 else
216 trace("ValueName: (null)\n");
218 switch(ValueType)
220 case REG_NONE:
221 trace("ValueType: REG_NONE\n");
222 trace("ValueData: %p\n", ValueData);
223 break;
225 case REG_BINARY:
226 trace("ValueType: REG_BINARY\n");
227 trace("ValueData: %p\n", ValueData);
228 break;
230 case REG_SZ:
231 trace("ValueType: REG_SZ\n");
232 trace("ValueData: %s\n", (char*)ValueData);
233 break;
235 case REG_MULTI_SZ:
236 trace("ValueType: REG_MULTI_SZ\n");
237 trace("ValueData: %s\n", (char*)ValueData);
238 break;
240 case REG_EXPAND_SZ:
241 trace("ValueType: REG_EXPAND_SZ\n");
242 trace("ValueData: %s\n", (char*)ValueData);
243 break;
245 case REG_DWORD:
246 trace("ValueType: REG_DWORD\n");
247 trace("ValueData: %p\n", ValueData);
248 break;
250 trace("ValueLength: %d\n", (int)ValueLength);
252 if(CurrentTest == 0)
253 ok(1, "\n"); /*checks that QueryRoutine is called*/
254 if(CurrentTest > 7)
255 ok(!1, "Invalid Test Specified!\n");
257 CurrentTest++;
259 if(ValName)
260 pRtlFreeHeap(GetProcessHeap(), 0, ValName);
262 return ret;
265 static void test_RtlQueryRegistryValues(void)
269 ******************************
270 * QueryTable Flags *
271 ******************************
272 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
273 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
274 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
275 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
276 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
277 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
278 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
279 ******************************
282 **Test layout(numbered according to CurrentTest value)**
283 0)NOVALUE Just make sure call-back works
284 1)Null Name See if QueryRoutine is called for every value in current key
285 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
286 3)REQUIRED Test for value that's not there
287 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
288 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
289 6)DefaultType Test return values when key isn't present
290 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
291 8)DefaultLength Test Default Length with DefaultType = REG_SZ
292 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
293 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
294 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
295 12)Delete Try to delete value key
298 NTSTATUS status;
299 ULONG RelativeTo;
301 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
302 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
304 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
306 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
308 QueryTable[0].QueryRoutine = QueryRoutine;
309 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
310 QueryTable[0].Name = NULL;
311 QueryTable[0].EntryContext = NULL;
312 QueryTable[0].DefaultType = REG_BINARY;
313 QueryTable[0].DefaultData = NULL;
314 QueryTable[0].DefaultLength = 100;
316 QueryTable[1].QueryRoutine = QueryRoutine;
317 QueryTable[1].Flags = 0;
318 QueryTable[1].Name = NULL;
319 QueryTable[1].EntryContext = 0;
320 QueryTable[1].DefaultType = REG_NONE;
321 QueryTable[1].DefaultData = NULL;
322 QueryTable[1].DefaultLength = 0;
324 QueryTable[2].QueryRoutine = NULL;
325 QueryTable[2].Flags = 0;
326 QueryTable[2].Name = NULL;
327 QueryTable[2].EntryContext = 0;
328 QueryTable[2].DefaultType = REG_NONE;
329 QueryTable[2].DefaultData = NULL;
330 QueryTable[2].DefaultLength = 0;
332 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
333 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
335 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
338 static void test_NtOpenKey(void)
340 HANDLE key;
341 NTSTATUS status;
342 OBJECT_ATTRIBUTES attr;
343 ACCESS_MASK am = KEY_READ;
345 /* All NULL */
346 status = pNtOpenKey(NULL, 0, NULL);
347 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
349 /* NULL attributes */
350 status = pNtOpenKey(&key, 0, NULL);
351 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
352 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
354 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
356 /* NULL key */
357 status = pNtOpenKey(NULL, am, &attr);
358 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
360 /* Length > sizeof(OBJECT_ATTRIBUTES) */
361 attr.Length *= 2;
362 status = pNtOpenKey(&key, am, &attr);
363 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
366 static void test_NtCreateKey(void)
368 /*Create WineTest*/
369 OBJECT_ATTRIBUTES attr;
370 HANDLE key;
371 ACCESS_MASK am = GENERIC_ALL;
372 NTSTATUS status;
374 /* All NULL */
375 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
376 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
377 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
379 /* Only the key */
380 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
381 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
382 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
384 /* Only accessmask */
385 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
386 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
387 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
389 /* Key and accessmask */
390 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
391 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
392 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
394 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
396 /* Only attributes */
397 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
398 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
400 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
401 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
403 /* Length > sizeof(OBJECT_ATTRIBUTES) */
404 attr.Length *= 2;
405 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
406 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
408 pNtClose(key);
411 static void test_NtSetValueKey(void)
413 HANDLE key;
414 NTSTATUS status;
415 OBJECT_ATTRIBUTES attr;
416 ACCESS_MASK am = KEY_WRITE;
417 UNICODE_STRING ValName;
418 DWORD data = 711;
420 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
421 status = pNtOpenKey(&key, am, &attr);
422 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
424 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
425 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
426 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
427 pRtlFreeUnicodeString(&ValName);
429 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
430 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
431 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
432 pRtlFreeUnicodeString(&ValName);
434 pNtClose(key);
437 static void test_RtlOpenCurrentUser(void)
439 NTSTATUS status;
440 HANDLE handle;
441 status=pRtlOpenCurrentUser(KEY_READ, &handle);
442 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
443 pNtClose(handle);
446 static void test_RtlCheckRegistryKey(void)
448 NTSTATUS status;
450 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
451 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
453 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
454 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
457 static void test_NtFlushKey(void)
459 NTSTATUS status;
460 HANDLE hkey;
461 OBJECT_ATTRIBUTES attr;
462 ACCESS_MASK am = KEY_ALL_ACCESS;
464 status = pNtFlushKey(NULL);
465 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
467 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
468 pNtOpenKey(&hkey, am, &attr);
470 status = pNtFlushKey(hkey);
471 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
473 pNtClose(hkey);
476 static void test_NtQueryValueKey(void)
478 HANDLE key;
479 NTSTATUS status;
480 OBJECT_ATTRIBUTES attr;
481 UNICODE_STRING ValName;
482 KEY_VALUE_BASIC_INFORMATION *basic_info;
483 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
484 KEY_VALUE_FULL_INFORMATION *full_info;
485 DWORD len, expected;
487 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
489 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
490 status = pNtOpenKey(&key, KEY_READ, &attr);
491 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
493 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
494 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
495 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
496 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
497 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
498 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
499 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
500 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
502 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
503 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
504 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
505 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
506 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
507 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
508 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
509 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
510 HeapFree(GetProcessHeap(), 0, basic_info);
512 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
513 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
514 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
515 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
516 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
517 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
518 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
519 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
521 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
522 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
523 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
524 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
525 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
526 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
527 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
528 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
529 HeapFree(GetProcessHeap(), 0, partial_info);
531 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
532 full_info = HeapAlloc(GetProcessHeap(), 0, len);
533 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
534 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
535 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
536 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
537 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
538 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
539 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
540 "NtQueryValueKey returned wrong len %d\n", len);
541 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
543 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
544 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
545 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
546 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
547 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
548 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
549 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
550 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
551 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
552 *(DWORD *)((char *)full_info + full_info->DataOffset));
553 HeapFree(GetProcessHeap(), 0, full_info);
555 pRtlFreeUnicodeString(&ValName);
556 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
558 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
559 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
560 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
561 memset(partial_info, 0xbd, len+1);
562 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
563 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
564 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
565 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
566 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
567 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
568 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
570 expected = len;
571 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
572 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
573 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
574 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
575 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
576 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
577 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
578 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
579 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
580 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
581 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
582 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
584 HeapFree(GetProcessHeap(), 0, partial_info);
586 pRtlFreeUnicodeString(&ValName);
587 pNtClose(key);
590 static void test_NtDeleteKey(void)
592 NTSTATUS status;
593 HANDLE hkey;
594 OBJECT_ATTRIBUTES attr;
595 ACCESS_MASK am = KEY_ALL_ACCESS;
597 status = pNtDeleteKey(NULL);
598 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
600 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
601 status = pNtOpenKey(&hkey, am, &attr);
603 status = pNtDeleteKey(hkey);
604 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
607 static void test_RtlpNtQueryValueKey(void)
609 NTSTATUS status;
611 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
612 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
615 static void test_symlinks(void)
617 static const WCHAR linkW[] = {'l','i','n','k',0};
618 static const WCHAR valueW[] = {'v','a','l','u','e',0};
619 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
620 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
621 static UNICODE_STRING null_str;
622 char buffer[1024];
623 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
624 WCHAR *target;
625 UNICODE_STRING symlink_str, link_str, target_str, value_str;
626 HANDLE root, key, link;
627 OBJECT_ATTRIBUTES attr;
628 NTSTATUS status;
629 DWORD target_len, len, dw;
631 pRtlInitUnicodeString( &link_str, linkW );
632 pRtlInitUnicodeString( &symlink_str, symlinkW );
633 pRtlInitUnicodeString( &target_str, targetW + 1 );
634 pRtlInitUnicodeString( &value_str, valueW );
636 target_len = winetestpath.Length + sizeof(targetW);
637 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
638 memcpy( target, winetestpath.Buffer, winetestpath.Length );
639 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
641 attr.Length = sizeof(attr);
642 attr.RootDirectory = 0;
643 attr.Attributes = 0;
644 attr.ObjectName = &winetestpath;
645 attr.SecurityDescriptor = NULL;
646 attr.SecurityQualityOfService = NULL;
648 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
649 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
651 attr.RootDirectory = root;
652 attr.ObjectName = &link_str;
653 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
654 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
656 /* REG_SZ is not allowed */
657 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
658 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
659 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
660 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
661 /* other values are not allowed */
662 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
663 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
665 /* try opening the target through the link */
667 attr.ObjectName = &link_str;
668 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
669 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
671 attr.ObjectName = &target_str;
672 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
673 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
675 dw = 0xbeef;
676 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
677 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
678 pNtClose( key );
680 attr.ObjectName = &link_str;
681 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
682 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
684 len = sizeof(buffer);
685 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
686 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
687 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
689 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
690 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
692 /* REG_LINK can be created in non-link keys */
693 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
694 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
695 len = sizeof(buffer);
696 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
697 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
698 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
699 "wrong len %u\n", len );
700 status = pNtDeleteValueKey( key, &symlink_str );
701 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
703 pNtClose( key );
705 attr.Attributes = 0;
706 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
707 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
709 len = sizeof(buffer);
710 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
711 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
712 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
714 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
715 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
716 pNtClose( key );
718 /* now open the symlink itself */
720 attr.RootDirectory = root;
721 attr.Attributes = OBJ_OPENLINK;
722 attr.ObjectName = &link_str;
723 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
724 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
726 len = sizeof(buffer);
727 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
728 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
729 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
730 "wrong len %u\n", len );
731 pNtClose( key );
733 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
734 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
735 len = sizeof(buffer);
736 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
737 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
738 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
739 "wrong len %u\n", len );
740 pNtClose( key );
742 if (0) /* crashes the Windows kernel on some Vista systems */
744 /* reopen the link from itself */
746 attr.RootDirectory = link;
747 attr.Attributes = OBJ_OPENLINK;
748 attr.ObjectName = &null_str;
749 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
750 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
751 len = sizeof(buffer);
752 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
753 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
754 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
755 "wrong len %u\n", len );
756 pNtClose( key );
758 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
759 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
760 len = sizeof(buffer);
761 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
762 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
763 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
764 "wrong len %u\n", len );
765 pNtClose( key );
768 if (0) /* crashes the Windows kernel in most versions */
770 attr.RootDirectory = link;
771 attr.Attributes = 0;
772 attr.ObjectName = &null_str;
773 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
774 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
775 len = sizeof(buffer);
776 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
777 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
778 pNtClose( key );
780 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
781 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
782 len = sizeof(buffer);
783 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
784 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
785 pNtClose( key );
788 /* target with terminating null doesn't work */
789 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
790 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
791 attr.RootDirectory = root;
792 attr.Attributes = 0;
793 attr.ObjectName = &link_str;
794 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
795 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
797 /* relative symlink, works only on win2k */
798 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
799 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
800 attr.ObjectName = &link_str;
801 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
802 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
803 "NtOpenKey wrong status 0x%08x\n", status );
805 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
806 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
808 status = pNtDeleteKey( link );
809 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
810 pNtClose( link );
812 attr.ObjectName = &target_str;
813 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
814 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
815 status = pNtDeleteKey( key );
816 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
817 pNtClose( key );
819 /* symlink loop */
821 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
822 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
823 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
824 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
825 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
826 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
828 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
829 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
830 "NtOpenKey failed: 0x%08x\n", status );
832 attr.Attributes = OBJ_OPENLINK;
833 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
834 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
835 pNtClose( key );
837 status = pNtDeleteKey( link );
838 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
839 pNtClose( link );
841 status = pNtDeleteKey( root );
842 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
843 pNtClose( root );
845 pRtlFreeHeap(GetProcessHeap(), 0, target);
848 static WCHAR valueW[] = {'v','a','l','u','e'};
849 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
850 static const DWORD ptr_size = 8 * sizeof(void*);
852 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
854 char tmp[32];
855 NTSTATUS status;
856 OBJECT_ATTRIBUTES attr;
857 UNICODE_STRING str;
858 HANDLE key;
859 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
860 DWORD dw, len = sizeof(tmp);
862 attr.Length = sizeof(attr);
863 attr.RootDirectory = root;
864 attr.Attributes = OBJ_CASE_INSENSITIVE;
865 attr.ObjectName = &str;
866 attr.SecurityDescriptor = NULL;
867 attr.SecurityQualityOfService = NULL;
868 pRtlCreateUnicodeStringFromAsciiz( &str, name );
870 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
871 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
872 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
874 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
875 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
876 dw = 0;
877 else
879 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
880 dw = *(DWORD *)info->Data;
882 pNtClose( key );
883 pRtlFreeUnicodeString( &str );
884 return dw;
887 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
889 DWORD dw = get_key_value( root, name, flags );
890 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
892 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
894 static void test_redirection(void)
896 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
897 'M','a','c','h','i','n','e','\\',
898 'S','o','f','t','w','a','r','e',0};
899 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
900 'M','a','c','h','i','n','e','\\',
901 'S','o','f','t','w','a','r','e','\\',
902 'W','o','w','6','4','3','2','N','o','d','e',0};
903 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
904 'M','a','c','h','i','n','e','\\',
905 'S','o','f','t','w','a','r','e','\\',
906 'W','i','n','e',0};
907 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
908 'M','a','c','h','i','n','e','\\',
909 'S','o','f','t','w','a','r','e','\\',
910 'W','o','w','6','4','3','2','N','o','d','e','\\',
911 'W','i','n','e',0};
912 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
913 'M','a','c','h','i','n','e','\\',
914 'S','o','f','t','w','a','r','e','\\',
915 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
916 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
917 'M','a','c','h','i','n','e','\\',
918 'S','o','f','t','w','a','r','e','\\',
919 'W','o','w','6','4','3','2','N','o','d','e','\\',
920 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
921 NTSTATUS status;
922 OBJECT_ATTRIBUTES attr;
923 UNICODE_STRING str;
924 char buffer[1024];
925 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
926 DWORD dw, len;
927 HANDLE key, root32, root64, key32, key64;
928 BOOL is_vista = FALSE;
930 if (ptr_size != 64)
932 ULONG is_wow64, len;
933 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
934 &is_wow64, sizeof(is_wow64), &len ) ||
935 !is_wow64)
937 trace( "Not on Wow64, no redirection\n" );
938 return;
942 attr.Length = sizeof(attr);
943 attr.RootDirectory = 0;
944 attr.Attributes = OBJ_CASE_INSENSITIVE;
945 attr.ObjectName = &str;
946 attr.SecurityDescriptor = NULL;
947 attr.SecurityQualityOfService = NULL;
949 pRtlInitUnicodeString( &str, wine64W );
950 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
951 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
953 pRtlInitUnicodeString( &str, wine32W );
954 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
955 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
957 pRtlInitUnicodeString( &str, key64W );
958 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
959 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
961 pRtlInitUnicodeString( &str, key32W );
962 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
963 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
965 dw = 64;
966 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
967 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
969 dw = 32;
970 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
971 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
973 len = sizeof(buffer);
974 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
975 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
976 dw = *(DWORD *)info->Data;
977 ok( dw == 32, "wrong value %u\n", dw );
979 len = sizeof(buffer);
980 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
981 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
982 dw = *(DWORD *)info->Data;
983 ok( dw == 64, "wrong value %u\n", dw );
985 pRtlInitUnicodeString( &str, softwareW );
986 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
987 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
989 if (ptr_size == 32)
991 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
992 /* the new (and simpler) Win7 mechanism doesn't */
993 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
995 trace( "using Vista-style Wow6432Node handling\n" );
996 is_vista = TRUE;
998 check_key_value( key, "Wine\\Winetest", 0, 32 );
999 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1000 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1001 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1002 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1003 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1005 else
1007 check_key_value( key, "Wine\\Winetest", 0, 64 );
1008 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1010 pNtClose( key );
1012 if (ptr_size == 32)
1014 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1015 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1016 dw = get_key_value( key, "Wine\\Winetest", 0 );
1017 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1018 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1019 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1020 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1021 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1022 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1023 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1024 pNtClose( key );
1026 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1027 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1028 check_key_value( key, "Wine\\Winetest", 0, 32 );
1029 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1030 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1031 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1032 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1033 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1034 pNtClose( key );
1037 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1038 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1039 if (ptr_size == 64)
1041 /* KEY_WOW64 flags have no effect on 64-bit */
1042 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1043 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1044 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1045 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1047 else
1049 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1050 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1051 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1052 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1055 pRtlInitUnicodeString( &str, wownodeW );
1056 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1057 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1058 check_key_value( key, "Wine\\Winetest", 0, 32 );
1059 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1060 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1061 pNtClose( key );
1063 if (ptr_size == 32)
1065 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1066 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1067 dw = get_key_value( key, "Wine\\Winetest", 0 );
1068 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1069 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1070 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1071 pNtClose( key );
1073 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1074 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1075 check_key_value( key, "Wine\\Winetest", 0, 32 );
1076 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1077 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1078 pNtClose( key );
1081 pRtlInitUnicodeString( &str, wine32W );
1082 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1083 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1084 check_key_value( key, "Winetest", 0, 32 );
1085 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1086 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1087 pNtClose( key );
1089 if (ptr_size == 32)
1091 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1092 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1093 dw = get_key_value( key, "Winetest", 0 );
1094 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1095 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1096 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1097 pNtClose( key );
1099 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1100 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1101 check_key_value( key, "Winetest", 0, 32 );
1102 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1103 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1104 pNtClose( key );
1107 pRtlInitUnicodeString( &str, wine64W );
1108 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1109 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1110 check_key_value( key, "Winetest", 0, ptr_size );
1111 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1112 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1113 pNtClose( key );
1115 if (ptr_size == 32)
1117 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1118 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1119 dw = get_key_value( key, "Winetest", 0 );
1120 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1121 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1122 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1123 pNtClose( key );
1125 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1126 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1127 check_key_value( key, "Winetest", 0, 32 );
1128 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1129 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1130 pNtClose( key );
1133 status = pNtDeleteKey( key32 );
1134 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1135 pNtClose( key32 );
1137 status = pNtDeleteKey( key64 );
1138 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1139 pNtClose( key64 );
1141 pNtDeleteKey( root32 );
1142 pNtClose( root32 );
1143 pNtDeleteKey( root64 );
1144 pNtClose( root64 );
1147 START_TEST(reg)
1149 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1150 if(!InitFunctionPtrs())
1151 return;
1152 pRtlFormatCurrentUserKeyPath(&winetestpath);
1153 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1154 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1155 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1157 pRtlAppendUnicodeToString(&winetestpath, winetest);
1159 test_NtCreateKey();
1160 test_NtOpenKey();
1161 test_NtSetValueKey();
1162 test_RtlCheckRegistryKey();
1163 test_RtlOpenCurrentUser();
1164 test_RtlQueryRegistryValues();
1165 test_RtlpNtQueryValueKey();
1166 test_NtFlushKey();
1167 test_NtQueryValueKey();
1168 test_NtDeleteKey();
1169 test_symlinks();
1170 test_redirection();
1172 pRtlFreeUnicodeString(&winetestpath);
1174 FreeLibrary(hntdll);