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"
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
,
65 typedef struct _RTL_QUERY_REGISTRY_TABLE
{
66 PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
;
73 } RTL_QUERY_REGISTRY_TABLE
, *PRTL_QUERY_REGISTRY_TABLE
;
75 typedef struct _KEY_VALUE_BASIC_INFORMATION
{
80 } KEY_VALUE_BASIC_INFORMATION
, *PKEY_VALUE_BASIC_INFORMATION
;
82 typedef struct _KEY_VALUE_PARTIAL_INFORMATION
{
87 } KEY_VALUE_PARTIAL_INFORMATION
, *PKEY_VALUE_PARTIAL_INFORMATION
;
89 typedef struct _KEY_VALUE_FULL_INFORMATION
{
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) \
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; \
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
,
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); \
155 trace("GetProcAddress(%s) failed\n", #func); \
156 FreeLibrary(hntdll); \
160 static BOOL
InitFunctionPtrs(void)
162 hntdll
= LoadLibraryA("ntdll.dll");
164 trace("Could not load ntdll.dll\n");
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
)
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;
203 trace("**Test %d**\n", CurrentTest
);
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
);
216 trace("ValueName: (null)\n");
221 trace("ValueType: REG_NONE\n");
222 trace("ValueData: %p\n", ValueData
);
226 trace("ValueType: REG_BINARY\n");
227 trace("ValueData: %p\n", ValueData
);
231 trace("ValueType: REG_SZ\n");
232 trace("ValueData: %s\n", (char*)ValueData
);
236 trace("ValueType: REG_MULTI_SZ\n");
237 trace("ValueData: %s\n", (char*)ValueData
);
241 trace("ValueType: REG_EXPAND_SZ\n");
242 trace("ValueData: %s\n", (char*)ValueData
);
246 trace("ValueType: REG_DWORD\n");
247 trace("ValueData: %p\n", ValueData
);
250 trace("ValueLength: %d\n", (int)ValueLength
);
253 ok(1, "\n"); /*checks that QueryRoutine is called*/
255 ok(!1, "Invalid Test Specified!\n");
260 pRtlFreeHeap(GetProcessHeap(), 0, ValName
);
265 static void test_RtlQueryRegistryValues(void)
269 ******************************
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
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)
342 OBJECT_ATTRIBUTES attr
;
343 ACCESS_MASK am
= KEY_READ
;
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);
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) */
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)
369 OBJECT_ATTRIBUTES attr
;
371 ACCESS_MASK am
= GENERIC_ALL
;
376 status
= pNtCreateKey(NULL
, 0, NULL
, 0, 0, 0, 0);
377 ok(status
== STATUS_ACCESS_VIOLATION
|| status
== STATUS_INVALID_PARAMETER
,
378 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status
);
381 status
= pNtCreateKey(&key
, 0, NULL
, 0, 0, 0, 0);
382 ok(status
== STATUS_ACCESS_VIOLATION
/* W2K3/XP/W2K */ || status
== STATUS_INVALID_PARAMETER
/* NT4 */,
383 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status
);
385 /* Only accessmask */
386 status
= pNtCreateKey(NULL
, am
, NULL
, 0, 0, 0, 0);
387 ok(status
== STATUS_ACCESS_VIOLATION
|| status
== STATUS_INVALID_PARAMETER
,
388 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status
);
390 /* Key and accessmask */
391 status
= pNtCreateKey(&key
, am
, NULL
, 0, 0, 0, 0);
392 ok(status
== STATUS_ACCESS_VIOLATION
/* W2K3/XP/W2K */ || status
== STATUS_INVALID_PARAMETER
/* NT4 */,
393 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status
);
395 InitializeObjectAttributes(&attr
, &winetestpath
, 0, 0, 0);
397 /* Only attributes */
398 status
= pNtCreateKey(NULL
, 0, &attr
, 0, 0, 0, 0);
399 ok(status
== STATUS_ACCESS_VIOLATION
, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status
);
401 /* Length > sizeof(OBJECT_ATTRIBUTES) */
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 attr
.Length
= sizeof(attr
);
407 status
= pNtCreateKey(&key
, am
, &attr
, 0, 0, 0, 0);
408 ok(status
== STATUS_SUCCESS
, "NtCreateKey Failed: 0x%08x\n", status
);
410 attr
.RootDirectory
= key
;
411 attr
.ObjectName
= &str
;
413 pRtlCreateUnicodeStringFromAsciiz( &str
, "test\\sub\\key" );
414 status
= pNtCreateKey( &subkey
, am
, &attr
, 0, 0, 0, 0 );
415 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtCreateKey failed: 0x%08x\n", status
);
416 pRtlFreeUnicodeString( &str
);
418 pRtlCreateUnicodeStringFromAsciiz( &str
, "test\\subkey" );
419 status
= pNtCreateKey( &subkey
, am
, &attr
, 0, 0, 0, 0 );
420 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtCreateKey failed: 0x%08x\n", status
);
421 pRtlFreeUnicodeString( &str
);
423 pRtlCreateUnicodeStringFromAsciiz( &str
, "test\\subkey\\" );
424 status
= pNtCreateKey( &subkey
, am
, &attr
, 0, 0, 0, 0 );
425 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtCreateKey failed: 0x%08x\n", status
);
426 pRtlFreeUnicodeString( &str
);
428 pRtlCreateUnicodeStringFromAsciiz( &str
, "test_subkey\\" );
429 status
= pNtCreateKey( &subkey
, am
, &attr
, 0, 0, 0, 0 );
430 ok( status
== STATUS_SUCCESS
|| broken(status
== STATUS_OBJECT_NAME_NOT_FOUND
), /* nt4 */
431 "NtCreateKey failed: 0x%08x\n", status
);
432 if (status
== STATUS_SUCCESS
)
434 pNtDeleteKey( subkey
);
437 pRtlFreeUnicodeString( &str
);
439 pRtlCreateUnicodeStringFromAsciiz( &str
, "test_subkey" );
440 status
= pNtCreateKey( &subkey
, am
, &attr
, 0, 0, 0, 0 );
441 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
442 pRtlFreeUnicodeString( &str
);
443 pNtDeleteKey( subkey
);
449 static void test_NtSetValueKey(void)
453 OBJECT_ATTRIBUTES attr
;
454 ACCESS_MASK am
= KEY_WRITE
;
455 UNICODE_STRING ValName
;
458 InitializeObjectAttributes(&attr
, &winetestpath
, 0, 0, 0);
459 status
= pNtOpenKey(&key
, am
, &attr
);
460 ok(status
== STATUS_SUCCESS
, "NtOpenKey Failed: 0x%08x\n", status
);
462 pRtlCreateUnicodeStringFromAsciiz(&ValName
, "deletetest");
463 status
= pNtSetValueKey(key
, &ValName
, 0, REG_DWORD
, &data
, sizeof(data
));
464 ok(status
== STATUS_SUCCESS
, "NtSetValueKey Failed: 0x%08x\n", status
);
465 pRtlFreeUnicodeString(&ValName
);
467 pRtlCreateUnicodeStringFromAsciiz(&ValName
, "stringtest");
468 status
= pNtSetValueKey(key
, &ValName
, 0, REG_SZ
, (VOID
*)stringW
, STR_TRUNC_SIZE
);
469 ok(status
== STATUS_SUCCESS
, "NtSetValueKey Failed: 0x%08x\n", status
);
470 pRtlFreeUnicodeString(&ValName
);
475 static void test_RtlOpenCurrentUser(void)
479 status
=pRtlOpenCurrentUser(KEY_READ
, &handle
);
480 ok(status
== STATUS_SUCCESS
, "RtlOpenCurrentUser Failed: 0x%08x\n", status
);
484 static void test_RtlCheckRegistryKey(void)
488 status
= pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE
, winetestpath
.Buffer
);
489 ok(status
== STATUS_SUCCESS
, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status
);
491 status
= pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
), winetestpath
.Buffer
);
492 ok(status
== STATUS_SUCCESS
, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status
);
495 static void test_NtFlushKey(void)
499 OBJECT_ATTRIBUTES attr
;
500 ACCESS_MASK am
= KEY_ALL_ACCESS
;
502 status
= pNtFlushKey(NULL
);
503 ok(status
== STATUS_INVALID_HANDLE
, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status
);
505 InitializeObjectAttributes(&attr
, &winetestpath
, 0, 0, 0);
506 pNtOpenKey(&hkey
, am
, &attr
);
508 status
= pNtFlushKey(hkey
);
509 ok(status
== STATUS_SUCCESS
, "NtDeleteKey Failed: 0x%08x\n", status
);
514 static void test_NtQueryValueKey(void)
518 OBJECT_ATTRIBUTES attr
;
519 UNICODE_STRING ValName
;
520 KEY_VALUE_BASIC_INFORMATION
*basic_info
;
521 KEY_VALUE_PARTIAL_INFORMATION
*partial_info
;
522 KEY_VALUE_FULL_INFORMATION
*full_info
;
525 pRtlCreateUnicodeStringFromAsciiz(&ValName
, "deletetest");
527 InitializeObjectAttributes(&attr
, &winetestpath
, 0, 0, 0);
528 status
= pNtOpenKey(&key
, KEY_READ
, &attr
);
529 ok(status
== STATUS_SUCCESS
, "NtOpenKey Failed: 0x%08x\n", status
);
531 len
= FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[0]);
532 basic_info
= HeapAlloc(GetProcessHeap(), 0, len
);
533 status
= pNtQueryValueKey(key
, &ValName
, KeyValueBasicInformation
, basic_info
, len
, &len
);
534 ok(status
== STATUS_BUFFER_OVERFLOW
, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status
);
535 ok(basic_info
->TitleIndex
== 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info
->TitleIndex
);
536 ok(basic_info
->Type
== REG_DWORD
, "NtQueryValueKey returned wrong Type %d\n", basic_info
->Type
);
537 ok(basic_info
->NameLength
== 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info
->NameLength
);
538 ok(len
== FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[basic_info
->NameLength
/sizeof(WCHAR
)]), "NtQueryValueKey returned wrong len %d\n", len
);
540 basic_info
= HeapReAlloc(GetProcessHeap(), 0, basic_info
, len
);
541 status
= pNtQueryValueKey(key
, &ValName
, KeyValueBasicInformation
, basic_info
, len
, &len
);
542 ok(status
== STATUS_SUCCESS
, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status
);
543 ok(basic_info
->TitleIndex
== 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info
->TitleIndex
);
544 ok(basic_info
->Type
== REG_DWORD
, "NtQueryValueKey returned wrong Type %d\n", basic_info
->Type
);
545 ok(basic_info
->NameLength
== 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info
->NameLength
);
546 ok(len
== FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION
, Name
[basic_info
->NameLength
/sizeof(WCHAR
)]), "NtQueryValueKey returned wrong len %d\n", len
);
547 ok(!memcmp(basic_info
->Name
, ValName
.Buffer
, ValName
.Length
), "incorrect Name returned\n");
548 HeapFree(GetProcessHeap(), 0, basic_info
);
550 len
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
551 partial_info
= HeapAlloc(GetProcessHeap(), 0, len
);
552 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, partial_info
, len
, &len
);
553 ok(status
== STATUS_BUFFER_OVERFLOW
, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status
);
554 ok(partial_info
->TitleIndex
== 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info
->TitleIndex
);
555 ok(partial_info
->Type
== REG_DWORD
, "NtQueryValueKey returned wrong Type %d\n", partial_info
->Type
);
556 ok(partial_info
->DataLength
== 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info
->DataLength
);
557 ok(len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[partial_info
->DataLength
]), "NtQueryValueKey returned wrong len %d\n", len
);
559 partial_info
= HeapReAlloc(GetProcessHeap(), 0, partial_info
, len
);
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_DWORD
, "NtQueryValueKey returned wrong Type %d\n", partial_info
->Type
);
564 ok(partial_info
->DataLength
== 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info
->DataLength
);
565 ok(len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[partial_info
->DataLength
]), "NtQueryValueKey returned wrong len %d\n", len
);
566 ok(*(DWORD
*)partial_info
->Data
== 711, "incorrect Data returned: 0x%x\n", *(DWORD
*)partial_info
->Data
);
567 HeapFree(GetProcessHeap(), 0, partial_info
);
569 len
= FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]);
570 full_info
= HeapAlloc(GetProcessHeap(), 0, len
);
571 status
= pNtQueryValueKey(key
, &ValName
, KeyValueFullInformation
, full_info
, len
, &len
);
572 ok(status
== STATUS_BUFFER_OVERFLOW
, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status
);
573 ok(full_info
->TitleIndex
== 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info
->TitleIndex
);
574 ok(full_info
->Type
== REG_DWORD
, "NtQueryValueKey returned wrong Type %d\n", full_info
->Type
);
575 ok(full_info
->DataLength
== 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info
->DataLength
);
576 ok(full_info
->NameLength
== 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info
->NameLength
);
577 ok(len
== FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) + full_info
->DataLength
+ full_info
->NameLength
,
578 "NtQueryValueKey returned wrong len %d\n", len
);
579 len
= FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION
, Name
[0]) + full_info
->DataLength
+ full_info
->NameLength
;
581 full_info
= HeapReAlloc(GetProcessHeap(), 0, full_info
, len
);
582 status
= pNtQueryValueKey(key
, &ValName
, KeyValueFullInformation
, full_info
, len
, &len
);
583 ok(status
== STATUS_SUCCESS
, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status
);
584 ok(full_info
->TitleIndex
== 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info
->TitleIndex
);
585 ok(full_info
->Type
== REG_DWORD
, "NtQueryValueKey returned wrong Type %d\n", full_info
->Type
);
586 ok(full_info
->DataLength
== 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info
->DataLength
);
587 ok(full_info
->NameLength
== 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info
->NameLength
);
588 ok(!memcmp(full_info
->Name
, ValName
.Buffer
, ValName
.Length
), "incorrect Name returned\n");
589 ok(*(DWORD
*)((char *)full_info
+ full_info
->DataOffset
) == 711, "incorrect Data returned: 0x%x\n",
590 *(DWORD
*)((char *)full_info
+ full_info
->DataOffset
));
591 HeapFree(GetProcessHeap(), 0, full_info
);
593 pRtlFreeUnicodeString(&ValName
);
594 pRtlCreateUnicodeStringFromAsciiz(&ValName
, "stringtest");
596 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, NULL
, 0, &len
);
597 ok(status
== STATUS_BUFFER_TOO_SMALL
, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status
);
598 partial_info
= HeapAlloc(GetProcessHeap(), 0, len
+1);
599 memset(partial_info
, 0xbd, len
+1);
600 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, partial_info
, len
, &len
);
601 ok(status
== STATUS_SUCCESS
, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status
);
602 ok(partial_info
->TitleIndex
== 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info
->TitleIndex
);
603 ok(partial_info
->Type
== REG_SZ
, "NtQueryValueKey returned wrong Type %d\n", partial_info
->Type
);
604 ok(partial_info
->DataLength
== STR_TRUNC_SIZE
, "NtQueryValueKey returned wrong DataLength %d\n", partial_info
->DataLength
);
605 ok(!memcmp(partial_info
->Data
, stringW
, STR_TRUNC_SIZE
), "incorrect Data returned\n");
606 ok(*(partial_info
->Data
+STR_TRUNC_SIZE
) == 0xbd, "string overflowed %02x\n", *(partial_info
->Data
+STR_TRUNC_SIZE
));
609 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, partial_info
, 0, &len
);
610 ok(status
== STATUS_BUFFER_TOO_SMALL
, "NtQueryValueKey wrong status 0x%08x\n", status
);
611 ok(len
== expected
, "NtQueryValueKey wrong len %u\n", len
);
612 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, partial_info
, 1, &len
);
613 ok(status
== STATUS_BUFFER_TOO_SMALL
, "NtQueryValueKey wrong status 0x%08x\n", status
);
614 ok(len
== expected
, "NtQueryValueKey wrong len %u\n", len
);
615 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, partial_info
, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
) - 1, &len
);
616 ok(status
== STATUS_BUFFER_TOO_SMALL
, "NtQueryValueKey wrong status 0x%08x\n", status
);
617 ok(len
== expected
, "NtQueryValueKey wrong len %u\n", len
);
618 status
= pNtQueryValueKey(key
, &ValName
, KeyValuePartialInformation
, partial_info
, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
), &len
);
619 ok(status
== STATUS_BUFFER_OVERFLOW
, "NtQueryValueKey wrong status 0x%08x\n", status
);
620 ok(len
== expected
, "NtQueryValueKey wrong len %u\n", len
);
622 HeapFree(GetProcessHeap(), 0, partial_info
);
624 pRtlFreeUnicodeString(&ValName
);
628 static void test_NtDeleteKey(void)
632 OBJECT_ATTRIBUTES attr
;
633 ACCESS_MASK am
= KEY_ALL_ACCESS
;
635 status
= pNtDeleteKey(NULL
);
636 ok(status
== STATUS_INVALID_HANDLE
, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status
);
638 InitializeObjectAttributes(&attr
, &winetestpath
, 0, 0, 0);
639 status
= pNtOpenKey(&hkey
, am
, &attr
);
641 status
= pNtDeleteKey(hkey
);
642 ok(status
== STATUS_SUCCESS
, "NtDeleteKey Failed: 0x%08x\n", status
);
645 static void test_RtlpNtQueryValueKey(void)
649 status
= pRtlpNtQueryValueKey(NULL
, NULL
, NULL
, NULL
, NULL
);
650 ok(status
== STATUS_INVALID_HANDLE
, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status
);
653 static void test_symlinks(void)
655 static const WCHAR linkW
[] = {'l','i','n','k',0};
656 static const WCHAR valueW
[] = {'v','a','l','u','e',0};
657 static const WCHAR symlinkW
[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
658 static const WCHAR targetW
[] = {'\\','t','a','r','g','e','t',0};
659 static UNICODE_STRING null_str
;
661 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
663 UNICODE_STRING symlink_str
, link_str
, target_str
, value_str
;
664 HANDLE root
, key
, link
;
665 OBJECT_ATTRIBUTES attr
;
667 DWORD target_len
, len
, dw
;
669 pRtlInitUnicodeString( &link_str
, linkW
);
670 pRtlInitUnicodeString( &symlink_str
, symlinkW
);
671 pRtlInitUnicodeString( &target_str
, targetW
+ 1 );
672 pRtlInitUnicodeString( &value_str
, valueW
);
674 target_len
= winetestpath
.Length
+ sizeof(targetW
);
675 target
= pRtlAllocateHeap( GetProcessHeap(), 0, target_len
+ sizeof(targetW
) /*for loop test*/ );
676 memcpy( target
, winetestpath
.Buffer
, winetestpath
.Length
);
677 memcpy( target
+ winetestpath
.Length
/sizeof(WCHAR
), targetW
, sizeof(targetW
) );
679 attr
.Length
= sizeof(attr
);
680 attr
.RootDirectory
= 0;
682 attr
.ObjectName
= &winetestpath
;
683 attr
.SecurityDescriptor
= NULL
;
684 attr
.SecurityQualityOfService
= NULL
;
686 status
= pNtCreateKey( &root
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
687 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
689 attr
.RootDirectory
= root
;
690 attr
.ObjectName
= &link_str
;
691 status
= pNtCreateKey( &link
, KEY_ALL_ACCESS
, &attr
, 0, 0, REG_OPTION_CREATE_LINK
, 0 );
692 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
694 /* REG_SZ is not allowed */
695 status
= pNtSetValueKey( link
, &symlink_str
, 0, REG_SZ
, target
, target_len
);
696 ok( status
== STATUS_ACCESS_DENIED
, "NtSetValueKey wrong status 0x%08x\n", status
);
697 status
= pNtSetValueKey( link
, &symlink_str
, 0, REG_LINK
, target
, target_len
- sizeof(WCHAR
) );
698 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
699 /* other values are not allowed */
700 status
= pNtSetValueKey( link
, &link_str
, 0, REG_LINK
, target
, target_len
- sizeof(WCHAR
) );
701 ok( status
== STATUS_ACCESS_DENIED
, "NtSetValueKey wrong status 0x%08x\n", status
);
703 /* try opening the target through the link */
705 attr
.ObjectName
= &link_str
;
706 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
707 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtOpenKey wrong status 0x%08x\n", status
);
709 attr
.ObjectName
= &target_str
;
710 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
711 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
714 status
= pNtSetValueKey( key
, &value_str
, 0, REG_DWORD
, &dw
, sizeof(dw
) );
715 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
718 attr
.ObjectName
= &link_str
;
719 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
720 ok( status
== STATUS_SUCCESS
, "NtOpenKey failed: 0x%08x\n", status
);
722 len
= sizeof(buffer
);
723 status
= pNtQueryValueKey( key
, &value_str
, KeyValuePartialInformation
, info
, len
, &len
);
724 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
725 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + sizeof(DWORD
), "wrong len %u\n", len
);
727 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
728 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtQueryValueKey failed: 0x%08x\n", status
);
730 /* REG_LINK can be created in non-link keys */
731 status
= pNtSetValueKey( key
, &symlink_str
, 0, REG_LINK
, target
, target_len
- sizeof(WCHAR
) );
732 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
733 len
= sizeof(buffer
);
734 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
735 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
736 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + target_len
- sizeof(WCHAR
),
737 "wrong len %u\n", len
);
738 status
= pNtDeleteValueKey( key
, &symlink_str
);
739 ok( status
== STATUS_SUCCESS
, "NtDeleteValueKey failed: 0x%08x\n", status
);
744 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
745 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
747 len
= sizeof(buffer
);
748 status
= pNtQueryValueKey( key
, &value_str
, KeyValuePartialInformation
, info
, len
, &len
);
749 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
750 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + sizeof(DWORD
), "wrong len %u\n", len
);
752 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
753 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtQueryValueKey failed: 0x%08x\n", status
);
756 /* now open the symlink itself */
758 attr
.RootDirectory
= root
;
759 attr
.Attributes
= OBJ_OPENLINK
;
760 attr
.ObjectName
= &link_str
;
761 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
762 ok( status
== STATUS_SUCCESS
, "NtOpenKey failed: 0x%08x\n", status
);
764 len
= sizeof(buffer
);
765 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
766 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
767 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + target_len
- sizeof(WCHAR
),
768 "wrong len %u\n", len
);
771 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
772 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
773 len
= sizeof(buffer
);
774 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
775 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
776 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + target_len
- sizeof(WCHAR
),
777 "wrong len %u\n", len
);
780 if (0) /* crashes the Windows kernel on some Vista systems */
782 /* reopen the link from itself */
784 attr
.RootDirectory
= link
;
785 attr
.Attributes
= OBJ_OPENLINK
;
786 attr
.ObjectName
= &null_str
;
787 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
788 ok( status
== STATUS_SUCCESS
, "NtOpenKey failed: 0x%08x\n", status
);
789 len
= sizeof(buffer
);
790 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
791 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
792 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + target_len
- sizeof(WCHAR
),
793 "wrong len %u\n", len
);
796 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
797 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
798 len
= sizeof(buffer
);
799 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
800 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
801 ok( len
== FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,Data
) + target_len
- sizeof(WCHAR
),
802 "wrong len %u\n", len
);
806 if (0) /* crashes the Windows kernel in most versions */
808 attr
.RootDirectory
= link
;
810 attr
.ObjectName
= &null_str
;
811 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
812 ok( status
== STATUS_SUCCESS
, "NtOpenKey failed: 0x%08x\n", status
);
813 len
= sizeof(buffer
);
814 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
815 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtQueryValueKey failed: 0x%08x\n", status
);
818 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
819 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
820 len
= sizeof(buffer
);
821 status
= pNtQueryValueKey( key
, &symlink_str
, KeyValuePartialInformation
, info
, len
, &len
);
822 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtQueryValueKey failed: 0x%08x\n", status
);
826 /* target with terminating null doesn't work */
827 status
= pNtSetValueKey( link
, &symlink_str
, 0, REG_LINK
, target
, target_len
);
828 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
829 attr
.RootDirectory
= root
;
831 attr
.ObjectName
= &link_str
;
832 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
833 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "NtOpenKey wrong status 0x%08x\n", status
);
835 /* relative symlink, works only on win2k */
836 status
= pNtSetValueKey( link
, &symlink_str
, 0, REG_LINK
, targetW
+1, sizeof(targetW
)-2*sizeof(WCHAR
) );
837 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
838 attr
.ObjectName
= &link_str
;
839 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
840 ok( status
== STATUS_SUCCESS
|| status
== STATUS_OBJECT_NAME_NOT_FOUND
,
841 "NtOpenKey wrong status 0x%08x\n", status
);
843 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, REG_OPTION_CREATE_LINK
, 0 );
844 ok( status
== STATUS_OBJECT_NAME_COLLISION
, "NtCreateKey failed: 0x%08x\n", status
);
846 status
= pNtDeleteKey( link
);
847 ok( status
== STATUS_SUCCESS
, "NtDeleteKey failed: 0x%08x\n", status
);
850 attr
.ObjectName
= &target_str
;
851 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
852 ok( status
== STATUS_SUCCESS
, "NtOpenKey failed: 0x%08x\n", status
);
853 status
= pNtDeleteKey( key
);
854 ok( status
== STATUS_SUCCESS
, "NtDeleteKey failed: 0x%08x\n", status
);
859 status
= pNtCreateKey( &link
, KEY_ALL_ACCESS
, &attr
, 0, 0, REG_OPTION_CREATE_LINK
, 0 );
860 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
861 memcpy( target
+ target_len
/sizeof(WCHAR
) - 1, targetW
, sizeof(targetW
) );
862 status
= pNtSetValueKey( link
, &symlink_str
, 0, REG_LINK
,
863 target
, target_len
+ sizeof(targetW
) - sizeof(WCHAR
) );
864 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
866 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
867 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
|| status
== STATUS_NAME_TOO_LONG
,
868 "NtOpenKey failed: 0x%08x\n", status
);
870 attr
.Attributes
= OBJ_OPENLINK
;
871 status
= pNtOpenKey( &key
, KEY_ALL_ACCESS
, &attr
);
872 ok( status
== STATUS_SUCCESS
, "NtOpenKey failed: 0x%08x\n", status
);
875 status
= pNtDeleteKey( link
);
876 ok( status
== STATUS_SUCCESS
, "NtDeleteKey failed: 0x%08x\n", status
);
879 status
= pNtDeleteKey( root
);
880 ok( status
== STATUS_SUCCESS
, "NtDeleteKey failed: 0x%08x\n", status
);
883 pRtlFreeHeap(GetProcessHeap(), 0, target
);
886 static WCHAR valueW
[] = {'v','a','l','u','e'};
887 static UNICODE_STRING value_str
= { sizeof(valueW
), sizeof(valueW
), valueW
};
888 static const DWORD ptr_size
= 8 * sizeof(void*);
890 static DWORD
get_key_value( HANDLE root
, const char *name
, DWORD flags
)
894 OBJECT_ATTRIBUTES attr
;
897 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)tmp
;
898 DWORD dw
, len
= sizeof(tmp
);
900 attr
.Length
= sizeof(attr
);
901 attr
.RootDirectory
= root
;
902 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
903 attr
.ObjectName
= &str
;
904 attr
.SecurityDescriptor
= NULL
;
905 attr
.SecurityQualityOfService
= NULL
;
906 pRtlCreateUnicodeStringFromAsciiz( &str
, name
);
908 status
= pNtCreateKey( &key
, flags
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
909 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
) return 0;
910 ok( status
== STATUS_SUCCESS
, "%08x: NtCreateKey failed: 0x%08x\n", flags
, status
);
912 status
= pNtQueryValueKey( key
, &value_str
, KeyValuePartialInformation
, info
, len
, &len
);
913 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
917 ok( status
== STATUS_SUCCESS
, "%08x: NtQueryValueKey failed: 0x%08x\n", flags
, status
);
918 dw
= *(DWORD
*)info
->Data
;
921 pRtlFreeUnicodeString( &str
);
925 static void _check_key_value( int line
, HANDLE root
, const char *name
, DWORD flags
, DWORD expect
)
927 DWORD dw
= get_key_value( root
, name
, flags
);
928 ok_(__FILE__
,line
)( dw
== expect
, "%08x: wrong value %u/%u\n", flags
, dw
, expect
);
930 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
932 static void test_redirection(void)
934 static const WCHAR softwareW
[] = {'\\','R','e','g','i','s','t','r','y','\\',
935 'M','a','c','h','i','n','e','\\',
936 'S','o','f','t','w','a','r','e',0};
937 static const WCHAR wownodeW
[] = {'\\','R','e','g','i','s','t','r','y','\\',
938 'M','a','c','h','i','n','e','\\',
939 'S','o','f','t','w','a','r','e','\\',
940 'W','o','w','6','4','3','2','N','o','d','e',0};
941 static const WCHAR wine64W
[] = {'\\','R','e','g','i','s','t','r','y','\\',
942 'M','a','c','h','i','n','e','\\',
943 'S','o','f','t','w','a','r','e','\\',
945 static const WCHAR wine32W
[] = {'\\','R','e','g','i','s','t','r','y','\\',
946 'M','a','c','h','i','n','e','\\',
947 'S','o','f','t','w','a','r','e','\\',
948 'W','o','w','6','4','3','2','N','o','d','e','\\',
950 static const WCHAR key64W
[] = {'\\','R','e','g','i','s','t','r','y','\\',
951 'M','a','c','h','i','n','e','\\',
952 'S','o','f','t','w','a','r','e','\\',
953 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
954 static const WCHAR key32W
[] = {'\\','R','e','g','i','s','t','r','y','\\',
955 'M','a','c','h','i','n','e','\\',
956 'S','o','f','t','w','a','r','e','\\',
957 'W','o','w','6','4','3','2','N','o','d','e','\\',
958 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
960 OBJECT_ATTRIBUTES attr
;
963 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
965 HANDLE key
, root32
, root64
, key32
, key64
;
966 BOOL is_vista
= FALSE
;
971 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information
,
972 &is_wow64
, sizeof(is_wow64
), &len
) ||
975 trace( "Not on Wow64, no redirection\n" );
980 attr
.Length
= sizeof(attr
);
981 attr
.RootDirectory
= 0;
982 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
983 attr
.ObjectName
= &str
;
984 attr
.SecurityDescriptor
= NULL
;
985 attr
.SecurityQualityOfService
= NULL
;
987 pRtlInitUnicodeString( &str
, wine64W
);
988 status
= pNtCreateKey( &root64
, KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
989 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
991 pRtlInitUnicodeString( &str
, wine32W
);
992 status
= pNtCreateKey( &root32
, KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
993 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
995 pRtlInitUnicodeString( &str
, key64W
);
996 status
= pNtCreateKey( &key64
, KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
997 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
999 pRtlInitUnicodeString( &str
, key32W
);
1000 status
= pNtCreateKey( &key32
, KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1001 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1004 status
= pNtSetValueKey( key64
, &value_str
, 0, REG_DWORD
, &dw
, sizeof(dw
) );
1005 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
1008 status
= pNtSetValueKey( key32
, &value_str
, 0, REG_DWORD
, &dw
, sizeof(dw
) );
1009 ok( status
== STATUS_SUCCESS
, "NtSetValueKey failed: 0x%08x\n", status
);
1011 len
= sizeof(buffer
);
1012 status
= pNtQueryValueKey( key32
, &value_str
, KeyValuePartialInformation
, info
, len
, &len
);
1013 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
1014 dw
= *(DWORD
*)info
->Data
;
1015 ok( dw
== 32, "wrong value %u\n", dw
);
1017 len
= sizeof(buffer
);
1018 status
= pNtQueryValueKey( key64
, &value_str
, KeyValuePartialInformation
, info
, len
, &len
);
1019 ok( status
== STATUS_SUCCESS
, "NtQueryValueKey failed: 0x%08x\n", status
);
1020 dw
= *(DWORD
*)info
->Data
;
1021 ok( dw
== 64, "wrong value %u\n", dw
);
1023 pRtlInitUnicodeString( &str
, softwareW
);
1024 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1025 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1029 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1030 /* the new (and simpler) Win7 mechanism doesn't */
1031 if (get_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1033 trace( "using Vista-style Wow6432Node handling\n" );
1036 check_key_value( key
, "Wine\\Winetest", 0, 32 );
1037 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1038 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1039 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, is_vista
? 32 : 0 );
1040 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 0 );
1041 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, is_vista
? 32 : 0 );
1045 check_key_value( key
, "Wine\\Winetest", 0, 64 );
1046 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1052 status
= pNtCreateKey( &key
, KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1053 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1054 dw
= get_key_value( key
, "Wine\\Winetest", 0 );
1055 ok( dw
== 64 || broken(dw
== 32) /* xp64 */, "wrong value %u\n", dw
);
1056 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
1057 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1058 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1059 dw
= get_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
);
1060 ok( dw
== 32 || broken(dw
== 64) /* xp64 */, "wrong value %u\n", dw
);
1061 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1064 status
= pNtCreateKey( &key
, KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1065 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1066 check_key_value( key
, "Wine\\Winetest", 0, 32 );
1067 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1068 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1069 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", 0, is_vista
? 32 : 0 );
1070 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 0 );
1071 check_key_value( key
, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, is_vista
? 32 : 0 );
1075 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size
);
1076 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1079 /* KEY_WOW64 flags have no effect on 64-bit */
1080 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
1081 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY
, 64 );
1082 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, 32 );
1083 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1087 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY
, 64 );
1088 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1089 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1090 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1093 pRtlInitUnicodeString( &str
, wownodeW
);
1094 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1095 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1096 check_key_value( key
, "Wine\\Winetest", 0, 32 );
1097 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, (ptr_size
== 64) ? 32 : (is_vista
? 64 : 32) );
1098 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1103 status
= pNtCreateKey( &key
, KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1104 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1105 dw
= get_key_value( key
, "Wine\\Winetest", 0 );
1106 ok( dw
== (is_vista
? 64 : 32) || broken(dw
== 32) /* xp64 */, "wrong value %u\n", dw
);
1107 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1108 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1111 status
= pNtCreateKey( &key
, KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1112 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1113 check_key_value( key
, "Wine\\Winetest", 0, 32 );
1114 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1115 check_key_value( key
, "Wine\\Winetest", KEY_WOW64_32KEY
, 32 );
1119 pRtlInitUnicodeString( &str
, wine32W
);
1120 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1121 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1122 check_key_value( key
, "Winetest", 0, 32 );
1123 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, (ptr_size
== 32 && is_vista
) ? 64 : 32 );
1124 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
1129 status
= pNtCreateKey( &key
, KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1130 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1131 dw
= get_key_value( key
, "Winetest", 0 );
1132 ok( dw
== 32 || (is_vista
&& dw
== 64), "wrong value %u\n", dw
);
1133 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1134 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
1137 status
= pNtCreateKey( &key
, KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1138 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1139 check_key_value( key
, "Winetest", 0, 32 );
1140 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1141 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
1145 pRtlInitUnicodeString( &str
, wine64W
);
1146 status
= pNtCreateKey( &key
, KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1147 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1148 check_key_value( key
, "Winetest", 0, ptr_size
);
1149 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : ptr_size
);
1150 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, ptr_size
);
1155 status
= pNtCreateKey( &key
, KEY_WOW64_64KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1156 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1157 dw
= get_key_value( key
, "Winetest", 0 );
1158 ok( dw
== 64 || broken(dw
== 32) /* xp64 */, "wrong value %u\n", dw
);
1159 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, 64 );
1160 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
1163 status
= pNtCreateKey( &key
, KEY_WOW64_32KEY
| KEY_ALL_ACCESS
, &attr
, 0, 0, 0, 0 );
1164 ok( status
== STATUS_SUCCESS
, "NtCreateKey failed: 0x%08x\n", status
);
1165 check_key_value( key
, "Winetest", 0, 32 );
1166 check_key_value( key
, "Winetest", KEY_WOW64_64KEY
, is_vista
? 64 : 32 );
1167 check_key_value( key
, "Winetest", KEY_WOW64_32KEY
, 32 );
1171 status
= pNtDeleteKey( key32
);
1172 ok( status
== STATUS_SUCCESS
, "NtDeleteKey failed: 0x%08x\n", status
);
1175 status
= pNtDeleteKey( key64
);
1176 ok( status
== STATUS_SUCCESS
, "NtDeleteKey failed: 0x%08x\n", status
);
1179 pNtDeleteKey( root32
);
1181 pNtDeleteKey( root64
);
1187 static const WCHAR winetest
[] = {'\\','W','i','n','e','T','e','s','t',0};
1188 if(!InitFunctionPtrs())
1190 pRtlFormatCurrentUserKeyPath(&winetestpath
);
1191 winetestpath
.Buffer
= pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, winetestpath
.Buffer
,
1192 winetestpath
.MaximumLength
+ sizeof(winetest
)*sizeof(WCHAR
));
1193 winetestpath
.MaximumLength
= winetestpath
.MaximumLength
+ sizeof(winetest
)*sizeof(WCHAR
);
1195 pRtlAppendUnicodeToString(&winetestpath
, winetest
);
1199 test_NtSetValueKey();
1200 test_RtlCheckRegistryKey();
1201 test_RtlOpenCurrentUser();
1202 test_RtlQueryRegistryValues();
1203 test_RtlpNtQueryValueKey();
1205 test_NtQueryValueKey();
1210 pRtlFreeUnicodeString(&winetestpath
);
1212 FreeLibrary(hntdll
);