ntdll/tests: Fix a couple of test failures on limited user accounts.
[wine.git] / dlls / ntdll / tests / reg.c
blobd00a4968336b906c9b0752d26e78045f47e8c0f2
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 BOOLEAN (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 * pNtOpenKeyEx)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG);
127 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
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 * pNtQueryKey)(HANDLE,KEY_INFORMATION_CLASS,PVOID,ULONG,PULONG);
134 static NTSTATUS (WINAPI * pNtQueryLicenseValue)(const UNICODE_STRING *,ULONG *,PVOID,ULONG,ULONG *);
135 static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
136 static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
137 ULONG, const void*, ULONG );
138 static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
139 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
140 static LONG (WINAPI * pRtlCompareUnicodeString)(const PUNICODE_STRING,const PUNICODE_STRING,BOOLEAN);
141 static BOOLEAN (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR);
142 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
143 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
144 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
145 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
146 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
147 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
148 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
149 static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN);
150 static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE,
151 void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN);
152 static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*);
154 static HMODULE hntdll = 0;
155 static int CurrentTest = 0;
156 static UNICODE_STRING winetestpath;
158 #define NTDLL_GET_PROC(func) \
159 p ## func = (void*)GetProcAddress(hntdll, #func); \
160 if(!p ## func) { \
161 trace("GetProcAddress(%s) failed\n", #func); \
162 FreeLibrary(hntdll); \
163 return FALSE; \
166 static BOOL InitFunctionPtrs(void)
168 hntdll = LoadLibraryA("ntdll.dll");
169 if(!hntdll) {
170 trace("Could not load ntdll.dll\n");
171 return FALSE;
173 NTDLL_GET_PROC(RtlInitUnicodeString)
174 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
175 NTDLL_GET_PROC(RtlCreateUnicodeString)
176 NTDLL_GET_PROC(RtlFreeUnicodeString)
177 NTDLL_GET_PROC(RtlQueryRegistryValues)
178 NTDLL_GET_PROC(RtlCheckRegistryKey)
179 NTDLL_GET_PROC(RtlOpenCurrentUser)
180 NTDLL_GET_PROC(NtClose)
181 NTDLL_GET_PROC(NtDeleteValueKey)
182 NTDLL_GET_PROC(NtCreateKey)
183 NTDLL_GET_PROC(NtFlushKey)
184 NTDLL_GET_PROC(NtDeleteKey)
185 NTDLL_GET_PROC(NtQueryKey)
186 NTDLL_GET_PROC(NtQueryValueKey)
187 NTDLL_GET_PROC(NtQueryInformationProcess)
188 NTDLL_GET_PROC(NtSetValueKey)
189 NTDLL_GET_PROC(NtOpenKey)
190 NTDLL_GET_PROC(NtNotifyChangeKey)
191 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
192 NTDLL_GET_PROC(RtlCompareUnicodeString)
193 NTDLL_GET_PROC(RtlReAllocateHeap)
194 NTDLL_GET_PROC(RtlAppendUnicodeToString)
195 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
196 NTDLL_GET_PROC(RtlFreeHeap)
197 NTDLL_GET_PROC(RtlAllocateHeap)
198 NTDLL_GET_PROC(RtlZeroMemory)
199 NTDLL_GET_PROC(RtlpNtQueryValueKey)
200 NTDLL_GET_PROC(RtlOpenCurrentUser)
201 NTDLL_GET_PROC(NtWaitForSingleObject)
203 /* optional functions */
204 pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue");
205 pNtOpenKeyEx = (void *)GetProcAddress(hntdll, "NtOpenKeyEx");
206 pNtNotifyChangeMultipleKeys = (void *)GetProcAddress(hntdll, "NtNotifyChangeMultipleKeys");
208 return TRUE;
210 #undef NTDLL_GET_PROC
212 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
213 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
215 NTSTATUS ret = STATUS_SUCCESS;
217 trace("**Test %d**\n", CurrentTest);
218 trace("ValueName: %s\n", wine_dbgstr_w(ValueName));
220 switch(ValueType)
222 case REG_NONE:
223 trace("ValueType: REG_NONE\n");
224 trace("ValueData: %p\n", ValueData);
225 break;
227 case REG_BINARY:
228 trace("ValueType: REG_BINARY\n");
229 trace("ValueData: %p\n", ValueData);
230 break;
232 case REG_SZ:
233 trace("ValueType: REG_SZ\n");
234 trace("ValueData: %s\n", (char*)ValueData);
235 break;
237 case REG_MULTI_SZ:
238 trace("ValueType: REG_MULTI_SZ\n");
239 trace("ValueData: %s\n", (char*)ValueData);
240 break;
242 case REG_EXPAND_SZ:
243 trace("ValueType: REG_EXPAND_SZ\n");
244 trace("ValueData: %s\n", (char*)ValueData);
245 break;
247 case REG_DWORD:
248 trace("ValueType: REG_DWORD\n");
249 trace("ValueData: %p\n", ValueData);
250 break;
252 trace("ValueLength: %d\n", (int)ValueLength);
254 if(CurrentTest == 0)
255 ok(1, "\n"); /*checks that QueryRoutine is called*/
256 if(CurrentTest > 7)
257 ok(!1, "Invalid Test Specified!\n");
259 CurrentTest++;
261 return ret;
264 static void test_RtlQueryRegistryValues(void)
268 ******************************
269 * QueryTable Flags *
270 ******************************
271 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
272 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
273 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
274 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
275 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
276 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
277 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
278 ******************************
281 **Test layout(numbered according to CurrentTest value)**
282 0)NOVALUE Just make sure call-back works
283 1)Null Name See if QueryRoutine is called for every value in current key
284 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
285 3)REQUIRED Test for value that's not there
286 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
287 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
288 6)DefaultType Test return values when key isn't present
289 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
290 8)DefaultLength Test Default Length with DefaultType = REG_SZ
291 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
292 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
293 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
294 12)Delete Try to delete value key
297 NTSTATUS status;
298 ULONG RelativeTo;
300 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
301 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
303 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
305 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
307 QueryTable[0].QueryRoutine = QueryRoutine;
308 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
309 QueryTable[0].Name = NULL;
310 QueryTable[0].EntryContext = NULL;
311 QueryTable[0].DefaultType = REG_BINARY;
312 QueryTable[0].DefaultData = NULL;
313 QueryTable[0].DefaultLength = 100;
315 QueryTable[1].QueryRoutine = QueryRoutine;
316 QueryTable[1].Flags = 0;
317 QueryTable[1].Name = NULL;
318 QueryTable[1].EntryContext = 0;
319 QueryTable[1].DefaultType = REG_NONE;
320 QueryTable[1].DefaultData = NULL;
321 QueryTable[1].DefaultLength = 0;
323 QueryTable[2].QueryRoutine = NULL;
324 QueryTable[2].Flags = 0;
325 QueryTable[2].Name = NULL;
326 QueryTable[2].EntryContext = 0;
327 QueryTable[2].DefaultType = REG_NONE;
328 QueryTable[2].DefaultData = NULL;
329 QueryTable[2].DefaultLength = 0;
331 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
332 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
334 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
337 static void test_NtOpenKey(void)
339 HANDLE key;
340 NTSTATUS status;
341 OBJECT_ATTRIBUTES attr;
342 ACCESS_MASK am = KEY_READ;
343 UNICODE_STRING str;
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);
365 /* Calling without parent key requres full registry path. */
366 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
367 InitializeObjectAttributes(&attr, &str, 0, 0, 0);
368 status = pNtOpenKey(&key, KEY_READ, &attr);
369 todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
370 pRtlFreeUnicodeString( &str );
372 /* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
373 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine" );
374 status = pNtOpenKey(&key, KEY_READ, &attr);
375 todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey Failed: 0x%08x\n", status);
377 attr.Attributes = OBJ_CASE_INSENSITIVE;
378 status = pNtOpenKey(&key, KEY_READ, &attr);
379 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
380 pNtClose(key);
381 pRtlFreeUnicodeString( &str );
383 pRtlCreateUnicodeStringFromAsciiz( &str, "" );
384 status = pNtOpenKey(&key, KEY_READ, &attr);
385 todo_wine
386 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
387 pRtlFreeUnicodeString( &str );
389 pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
390 status = pNtOpenKey(&key, KEY_READ, &attr);
391 todo_wine
392 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
393 pRtlFreeUnicodeString( &str );
395 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
396 status = pNtOpenKey(&key, KEY_READ, &attr);
397 todo_wine
398 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
399 pNtClose( key );
400 pRtlFreeUnicodeString( &str );
402 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
403 status = pNtOpenKey(&key, KEY_READ, &attr);
404 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
405 pNtClose( key );
406 pRtlFreeUnicodeString( &str );
408 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
409 status = pNtOpenKey(&key, KEY_READ, &attr);
410 todo_wine
411 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
412 pRtlFreeUnicodeString( &str );
414 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
415 status = pNtOpenKey(&key, KEY_READ, &attr);
416 todo_wine
417 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
418 pRtlFreeUnicodeString( &str );
420 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
421 status = pNtOpenKey(&key, KEY_READ, &attr);
422 todo_wine
423 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
424 pRtlFreeUnicodeString( &str );
426 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
427 status = pNtOpenKey(&key, KEY_READ, &attr);
428 todo_wine
429 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
430 pRtlFreeUnicodeString( &str );
432 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
433 status = pNtOpenKey(&key, KEY_READ, &attr);
434 todo_wine
435 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
436 pRtlFreeUnicodeString( &str );
438 if (!pNtOpenKeyEx)
440 win_skip("NtOpenKeyEx not available\n");
441 return;
444 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
445 status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0);
446 ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status);
448 pNtClose(key);
451 static void test_NtCreateKey(void)
453 /*Create WineTest*/
454 OBJECT_ATTRIBUTES attr;
455 HANDLE key, subkey;
456 ACCESS_MASK am = GENERIC_ALL;
457 NTSTATUS status;
458 UNICODE_STRING str;
460 /* All NULL */
461 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
462 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
463 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
465 /* Only the key */
466 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
467 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
468 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
470 /* Only accessmask */
471 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
472 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
473 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
475 /* Key and accessmask */
476 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
477 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
478 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
480 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
482 /* Only attributes */
483 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
484 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
485 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
487 /* Length > sizeof(OBJECT_ATTRIBUTES) */
488 attr.Length *= 2;
489 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
490 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
492 attr.Length = sizeof(attr);
493 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
494 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
496 attr.RootDirectory = key;
497 attr.ObjectName = &str;
499 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
500 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
501 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
502 pRtlFreeUnicodeString( &str );
504 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
505 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
506 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
507 pRtlFreeUnicodeString( &str );
509 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
510 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
511 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
512 pRtlFreeUnicodeString( &str );
514 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
515 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
516 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
517 "NtCreateKey failed: 0x%08x\n", status );
518 if (status == STATUS_SUCCESS)
520 pNtDeleteKey( subkey );
521 pNtClose( subkey );
523 pRtlFreeUnicodeString( &str );
525 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
526 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
527 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
528 pRtlFreeUnicodeString( &str );
529 pNtDeleteKey( subkey );
530 pNtClose( subkey );
532 attr.RootDirectory = 0;
533 attr.Attributes = OBJ_CASE_INSENSITIVE;
535 pRtlCreateUnicodeStringFromAsciiz( &str, "" );
536 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
537 todo_wine
538 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
539 pRtlFreeUnicodeString( &str );
541 pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
542 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
543 todo_wine
544 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
545 pRtlFreeUnicodeString( &str );
547 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
548 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
549 todo_wine
550 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
551 "NtCreateKey failed: 0x%08x\n", status );
552 if (!status) pNtClose( subkey );
553 pRtlFreeUnicodeString( &str );
555 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
556 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
557 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
558 "NtCreateKey failed: 0x%08x\n", status );
559 if (!status) pNtClose( subkey );
560 pRtlFreeUnicodeString( &str );
562 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
563 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
564 todo_wine
565 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
566 pRtlFreeUnicodeString( &str );
568 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
569 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
570 todo_wine
571 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
572 pRtlFreeUnicodeString( &str );
574 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
575 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
576 todo_wine
577 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
578 pRtlFreeUnicodeString( &str );
580 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
581 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
582 todo_wine
583 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
584 pRtlFreeUnicodeString( &str );
586 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
587 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
588 todo_wine
589 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
590 pRtlFreeUnicodeString( &str );
592 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
593 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
594 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
595 "NtCreateKey failed: 0x%08x\n", status );
596 if (!status) pNtClose( subkey );
597 pRtlFreeUnicodeString( &str );
599 /* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */
600 attr.Attributes = 0;
601 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
602 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
603 todo_wine
604 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
605 pRtlFreeUnicodeString( &str );
607 pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\Machine\\Software\\Classes" );
608 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
609 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
610 "NtCreateKey failed: 0x%08x\n", status );
611 if (!status) pNtClose( subkey );
612 pRtlFreeUnicodeString( &str );
614 pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" );
615 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
616 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
617 "NtCreateKey failed: 0x%08x\n", status );
618 if (!status) pNtClose( subkey );
619 pRtlFreeUnicodeString( &str );
621 pNtClose(key);
624 static void test_NtSetValueKey(void)
626 HANDLE key;
627 NTSTATUS status;
628 OBJECT_ATTRIBUTES attr;
629 ACCESS_MASK am = KEY_WRITE;
630 UNICODE_STRING ValName;
631 DWORD data = 711;
633 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
634 status = pNtOpenKey(&key, am, &attr);
635 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
637 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
638 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
639 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
640 pRtlFreeUnicodeString(&ValName);
642 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
643 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
644 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
645 pRtlFreeUnicodeString(&ValName);
647 pNtClose(key);
650 static void test_RtlOpenCurrentUser(void)
652 NTSTATUS status;
653 HANDLE handle;
654 status=pRtlOpenCurrentUser(KEY_READ, &handle);
655 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
656 pNtClose(handle);
659 static void test_RtlCheckRegistryKey(void)
661 NTSTATUS status;
663 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
664 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
666 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
667 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
670 static void test_NtFlushKey(void)
672 NTSTATUS status;
673 HANDLE hkey;
674 OBJECT_ATTRIBUTES attr;
675 ACCESS_MASK am = KEY_ALL_ACCESS;
677 status = pNtFlushKey(NULL);
678 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
680 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
681 pNtOpenKey(&hkey, am, &attr);
683 status = pNtFlushKey(hkey);
684 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
686 pNtClose(hkey);
689 static void test_NtQueryValueKey(void)
691 HANDLE key;
692 NTSTATUS status;
693 OBJECT_ATTRIBUTES attr;
694 UNICODE_STRING ValName;
695 KEY_VALUE_BASIC_INFORMATION *basic_info;
696 KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi;
697 KEY_VALUE_FULL_INFORMATION *full_info;
698 DWORD len, expected;
700 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
702 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
703 status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr);
704 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
706 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
707 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
708 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
709 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
710 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
711 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
712 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
713 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
715 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
716 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
717 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
718 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
719 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
720 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
721 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
722 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
723 HeapFree(GetProcessHeap(), 0, basic_info);
725 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
726 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
727 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
728 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
729 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
730 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
731 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
732 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
734 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
735 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
736 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
737 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
738 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
739 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
740 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
741 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
742 HeapFree(GetProcessHeap(), 0, partial_info);
744 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
745 full_info = HeapAlloc(GetProcessHeap(), 0, len);
746 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
747 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
748 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
749 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
750 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
751 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
752 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
753 "NtQueryValueKey returned wrong len %d\n", len);
754 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
756 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
757 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
758 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
759 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
760 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
761 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
762 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
763 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
764 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
765 *(DWORD *)((char *)full_info + full_info->DataOffset));
766 HeapFree(GetProcessHeap(), 0, full_info);
768 pRtlFreeUnicodeString(&ValName);
769 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
771 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
772 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
773 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
774 memset(partial_info, 0xbd, len+1);
775 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
776 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
777 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
778 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
779 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
780 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
781 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
783 expected = len;
784 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
785 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
786 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
787 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
788 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
789 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
790 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
791 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
792 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
793 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
794 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
795 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
797 HeapFree(GetProcessHeap(), 0, partial_info);
798 pRtlFreeUnicodeString(&ValName);
800 pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest");
801 status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0);
802 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
804 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
805 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
806 ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type);
807 ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength);
808 pRtlFreeUnicodeString(&ValName);
810 pNtClose(key);
813 static void test_NtDeleteKey(void)
815 NTSTATUS status;
816 HANDLE hkey;
817 OBJECT_ATTRIBUTES attr;
818 ACCESS_MASK am = KEY_ALL_ACCESS;
820 status = pNtDeleteKey(NULL);
821 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
823 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
824 status = pNtOpenKey(&hkey, am, &attr);
825 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
827 status = pNtDeleteKey(hkey);
828 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
831 static void test_NtQueryLicenseKey(void)
833 static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
834 UNICODE_STRING name;
835 WORD buffer[32];
836 NTSTATUS status;
837 ULONG type, len;
838 DWORD value;
840 if (!pNtQueryLicenseValue)
842 win_skip("NtQueryLicenseValue not found, skipping tests\n");
843 return;
846 type = 0xdead;
847 len = 0xbeef;
848 memset(&name, 0, sizeof(name));
849 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
850 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
851 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
852 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
854 /* test with empty key */
855 pRtlCreateUnicodeStringFromAsciiz(&name, "");
857 type = 0xdead;
858 len = 0xbeef;
859 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
860 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
861 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
862 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
864 type = 0xdead;
865 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
866 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
867 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
869 len = 0xbeef;
870 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
871 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
872 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
874 type = 0xdead;
875 len = 0xbeef;
876 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
877 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
878 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
879 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
881 pRtlFreeUnicodeString(&name);
883 /* test with nonexistent licence key */
884 pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
886 type = 0xdead;
887 len = 0xbeef;
888 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
889 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
890 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
891 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
893 type = 0xdead;
894 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
895 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
896 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
898 len = 0xbeef;
899 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
900 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
901 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
903 type = 0xdead;
904 len = 0xbeef;
905 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
906 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n");
907 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
908 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
910 pRtlFreeUnicodeString(&name);
912 /* test with REG_SZ license key */
913 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
915 type = 0xdead;
916 len = 0xbeef;
917 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
918 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
919 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
920 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
922 type = 0xdead;
923 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
924 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
925 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
927 type = 0xdead;
928 len = 0;
929 status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
930 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
931 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
932 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
934 len = 0;
935 status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
936 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
937 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
939 type = 0xdead;
940 len = 0;
941 memset(buffer, 0x11, sizeof(buffer));
942 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
943 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
944 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
945 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
946 ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
948 type = 0xdead;
949 len = 0;
950 memset(buffer, 0x11, sizeof(buffer));
951 status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
952 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
953 ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
954 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
955 ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
957 pRtlFreeUnicodeString(&name);
959 /* test with REG_DWORD license key */
960 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
962 type = 0xdead;
963 len = 0xbeef;
964 status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
965 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
966 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
967 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
969 type = 0xdead;
970 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
971 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
972 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
974 type = 0xdead;
975 len = 0;
976 status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
977 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
978 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
979 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
981 len = 0;
982 status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
983 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
984 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
986 type = 0xdead;
987 len = 0;
988 value = 0xdeadbeef;
989 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
990 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
991 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
992 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
993 ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
995 type = 0xdead;
996 len = 0;
997 status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
998 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
999 ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
1000 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1002 pRtlFreeUnicodeString(&name);
1005 static void test_RtlpNtQueryValueKey(void)
1007 NTSTATUS status;
1009 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
1010 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
1013 static void test_symlinks(void)
1015 static const WCHAR linkW[] = {'l','i','n','k',0};
1016 static const WCHAR valueW[] = {'v','a','l','u','e',0};
1017 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
1018 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
1019 static UNICODE_STRING null_str;
1020 char buffer[1024];
1021 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1022 WCHAR *target;
1023 UNICODE_STRING symlink_str, link_str, target_str, value_str;
1024 HANDLE root, key, link;
1025 OBJECT_ATTRIBUTES attr;
1026 NTSTATUS status;
1027 DWORD target_len, len, dw;
1029 pRtlInitUnicodeString( &link_str, linkW );
1030 pRtlInitUnicodeString( &symlink_str, symlinkW );
1031 pRtlInitUnicodeString( &target_str, targetW + 1 );
1032 pRtlInitUnicodeString( &value_str, valueW );
1034 target_len = winetestpath.Length + sizeof(targetW);
1035 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
1036 memcpy( target, winetestpath.Buffer, winetestpath.Length );
1037 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
1039 attr.Length = sizeof(attr);
1040 attr.RootDirectory = 0;
1041 attr.Attributes = 0;
1042 attr.ObjectName = &winetestpath;
1043 attr.SecurityDescriptor = NULL;
1044 attr.SecurityQualityOfService = NULL;
1046 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1047 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1049 attr.RootDirectory = root;
1050 attr.ObjectName = &link_str;
1051 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1052 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1054 /* REG_SZ is not allowed */
1055 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
1056 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1057 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1058 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1059 /* other values are not allowed */
1060 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1061 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1063 /* try opening the target through the link */
1065 attr.ObjectName = &link_str;
1066 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1067 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1069 attr.ObjectName = &target_str;
1070 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1071 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1073 dw = 0xbeef;
1074 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1075 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1076 pNtClose( key );
1078 attr.ObjectName = &link_str;
1079 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1080 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1082 len = sizeof(buffer);
1083 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1084 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1085 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1087 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1088 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1090 /* REG_LINK can be created in non-link keys */
1091 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1092 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1093 len = sizeof(buffer);
1094 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1095 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1096 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1097 "wrong len %u\n", len );
1098 status = pNtDeleteValueKey( key, &symlink_str );
1099 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
1101 pNtClose( key );
1103 attr.Attributes = 0;
1104 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1105 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1107 len = sizeof(buffer);
1108 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1109 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1110 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1112 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1113 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1114 pNtClose( key );
1116 /* now open the symlink itself */
1118 attr.RootDirectory = root;
1119 attr.Attributes = OBJ_OPENLINK;
1120 attr.ObjectName = &link_str;
1121 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1122 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1124 len = sizeof(buffer);
1125 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1126 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1127 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1128 "wrong len %u\n", len );
1129 pNtClose( key );
1131 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1132 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1133 len = sizeof(buffer);
1134 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1135 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1136 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1137 "wrong len %u\n", len );
1138 pNtClose( key );
1140 if (0) /* crashes the Windows kernel on some Vista systems */
1142 /* reopen the link from itself */
1144 attr.RootDirectory = link;
1145 attr.Attributes = OBJ_OPENLINK;
1146 attr.ObjectName = &null_str;
1147 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1148 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1149 len = sizeof(buffer);
1150 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1151 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1152 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1153 "wrong len %u\n", len );
1154 pNtClose( key );
1156 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1157 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1158 len = sizeof(buffer);
1159 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1160 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1161 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1162 "wrong len %u\n", len );
1163 pNtClose( key );
1166 if (0) /* crashes the Windows kernel in most versions */
1168 attr.RootDirectory = link;
1169 attr.Attributes = 0;
1170 attr.ObjectName = &null_str;
1171 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1172 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1173 len = sizeof(buffer);
1174 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1175 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1176 pNtClose( key );
1178 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1179 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1180 len = sizeof(buffer);
1181 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1182 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1183 pNtClose( key );
1186 /* target with terminating null doesn't work */
1187 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
1188 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1189 attr.RootDirectory = root;
1190 attr.Attributes = 0;
1191 attr.ObjectName = &link_str;
1192 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1193 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1195 /* relative symlink, works only on win2k */
1196 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
1197 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1198 attr.ObjectName = &link_str;
1199 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1200 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
1201 "NtOpenKey wrong status 0x%08x\n", status );
1203 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1204 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
1206 status = pNtDeleteKey( link );
1207 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1208 pNtClose( link );
1210 attr.ObjectName = &target_str;
1211 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1212 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1213 status = pNtDeleteKey( key );
1214 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1215 pNtClose( key );
1217 /* symlink loop */
1219 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1220 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1221 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
1222 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
1223 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
1224 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1226 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1227 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
1228 "NtOpenKey failed: 0x%08x\n", status );
1230 attr.Attributes = OBJ_OPENLINK;
1231 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1232 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1233 pNtClose( key );
1235 status = pNtDeleteKey( link );
1236 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1237 pNtClose( link );
1239 status = pNtDeleteKey( root );
1240 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1241 pNtClose( root );
1243 pRtlFreeHeap(GetProcessHeap(), 0, target);
1246 static WCHAR valueW[] = {'v','a','l','u','e'};
1247 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
1248 static const DWORD ptr_size = 8 * sizeof(void*);
1250 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
1252 char tmp[32];
1253 NTSTATUS status;
1254 OBJECT_ATTRIBUTES attr;
1255 UNICODE_STRING str;
1256 HANDLE key;
1257 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
1258 DWORD dw, len = sizeof(tmp);
1260 attr.Length = sizeof(attr);
1261 attr.RootDirectory = root;
1262 attr.Attributes = OBJ_CASE_INSENSITIVE;
1263 attr.ObjectName = &str;
1264 attr.SecurityDescriptor = NULL;
1265 attr.SecurityQualityOfService = NULL;
1266 pRtlCreateUnicodeStringFromAsciiz( &str, name );
1268 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1269 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
1270 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
1272 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1273 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1274 dw = 0;
1275 else
1277 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
1278 dw = *(DWORD *)info->Data;
1280 pNtClose( key );
1281 pRtlFreeUnicodeString( &str );
1282 return dw;
1285 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
1287 DWORD dw = get_key_value( root, name, flags );
1288 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
1290 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
1292 static void test_redirection(void)
1294 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1295 'M','a','c','h','i','n','e','\\',
1296 'S','o','f','t','w','a','r','e',0};
1297 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1298 'M','a','c','h','i','n','e','\\',
1299 'S','o','f','t','w','a','r','e','\\',
1300 'W','o','w','6','4','3','2','N','o','d','e',0};
1301 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1302 'M','a','c','h','i','n','e','\\',
1303 'S','o','f','t','w','a','r','e','\\',
1304 'W','i','n','e',0};
1305 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1306 'M','a','c','h','i','n','e','\\',
1307 'S','o','f','t','w','a','r','e','\\',
1308 'W','o','w','6','4','3','2','N','o','d','e','\\',
1309 'W','i','n','e',0};
1310 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1311 'M','a','c','h','i','n','e','\\',
1312 'S','o','f','t','w','a','r','e','\\',
1313 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
1314 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1315 'M','a','c','h','i','n','e','\\',
1316 'S','o','f','t','w','a','r','e','\\',
1317 'W','o','w','6','4','3','2','N','o','d','e','\\',
1318 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
1319 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1320 'M','a','c','h','i','n','e','\\',
1321 'S','o','f','t','w','a','r','e','\\',
1322 'C','l','a','s','s','e','s','\\',
1323 'W','i','n','e',0};
1324 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1325 'M','a','c','h','i','n','e','\\',
1326 'S','o','f','t','w','a','r','e','\\',
1327 'C','l','a','s','s','e','s','\\',
1328 'W','o','w','6','4','3','2','N','o','d','e','\\',
1329 'W','i','n','e',0};
1330 NTSTATUS status;
1331 OBJECT_ATTRIBUTES attr;
1332 UNICODE_STRING str;
1333 char buffer[1024];
1334 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1335 DWORD dw, len;
1336 HANDLE key, root32, root64, key32, key64;
1337 BOOL is_vista = FALSE;
1339 if (ptr_size != 64)
1341 ULONG is_wow64, len;
1342 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
1343 &is_wow64, sizeof(is_wow64), &len ) ||
1344 !is_wow64)
1346 trace( "Not on Wow64, no redirection\n" );
1347 return;
1351 attr.Length = sizeof(attr);
1352 attr.RootDirectory = 0;
1353 attr.Attributes = OBJ_CASE_INSENSITIVE;
1354 attr.ObjectName = &str;
1355 attr.SecurityDescriptor = NULL;
1356 attr.SecurityQualityOfService = NULL;
1358 pRtlInitUnicodeString( &str, wine64W );
1359 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1360 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1362 pRtlInitUnicodeString( &str, wine32W );
1363 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1364 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1366 pRtlInitUnicodeString( &str, key64W );
1367 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1368 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1370 pRtlInitUnicodeString( &str, key32W );
1371 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1372 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1374 dw = 64;
1375 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1376 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1378 dw = 32;
1379 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1380 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1382 len = sizeof(buffer);
1383 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1384 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1385 dw = *(DWORD *)info->Data;
1386 ok( dw == 32, "wrong value %u\n", dw );
1388 len = sizeof(buffer);
1389 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1390 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1391 dw = *(DWORD *)info->Data;
1392 ok( dw == 64, "wrong value %u\n", dw );
1394 pRtlInitUnicodeString( &str, softwareW );
1395 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1396 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1398 if (ptr_size == 32)
1400 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1401 /* the new (and simpler) Win7 mechanism doesn't */
1402 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1404 trace( "using Vista-style Wow6432Node handling\n" );
1405 is_vista = TRUE;
1407 check_key_value( key, "Wine\\Winetest", 0, 32 );
1408 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1409 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1410 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1411 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1412 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1414 else
1416 check_key_value( key, "Wine\\Winetest", 0, 64 );
1417 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1419 pNtClose( key );
1421 if (ptr_size == 32)
1423 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1424 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1425 dw = get_key_value( key, "Wine\\Winetest", 0 );
1426 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1427 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1428 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1429 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1430 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1431 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1432 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1433 pNtClose( key );
1435 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1436 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1437 check_key_value( key, "Wine\\Winetest", 0, 32 );
1438 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1439 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1440 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1441 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1442 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1443 pNtClose( key );
1446 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1447 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1448 if (ptr_size == 64)
1450 /* KEY_WOW64 flags have no effect on 64-bit */
1451 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1452 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1453 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1454 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1456 else
1458 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1459 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1460 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1461 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1464 pRtlInitUnicodeString( &str, wownodeW );
1465 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1466 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1467 check_key_value( key, "Wine\\Winetest", 0, 32 );
1468 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1469 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1470 pNtClose( key );
1472 if (ptr_size == 32)
1474 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1475 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1476 dw = get_key_value( key, "Wine\\Winetest", 0 );
1477 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1478 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1479 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1480 pNtClose( key );
1482 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1483 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1484 check_key_value( key, "Wine\\Winetest", 0, 32 );
1485 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1486 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1487 pNtClose( key );
1490 pRtlInitUnicodeString( &str, wine32W );
1491 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1492 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1493 check_key_value( key, "Winetest", 0, 32 );
1494 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1495 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1496 pNtClose( key );
1498 if (ptr_size == 32)
1500 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1501 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1502 dw = get_key_value( key, "Winetest", 0 );
1503 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1504 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1505 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1506 pNtClose( key );
1508 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1509 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1510 check_key_value( key, "Winetest", 0, 32 );
1511 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1512 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1513 pNtClose( key );
1516 pRtlInitUnicodeString( &str, wine64W );
1517 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1518 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1519 check_key_value( key, "Winetest", 0, ptr_size );
1520 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1521 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1522 pNtClose( key );
1524 if (ptr_size == 32)
1526 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1527 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1528 dw = get_key_value( key, "Winetest", 0 );
1529 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1530 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1531 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1532 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1533 pNtClose( key );
1535 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1536 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1537 check_key_value( key, "Winetest", 0, 32 );
1538 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1539 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1540 pNtClose( key );
1543 status = pNtDeleteKey( key32 );
1544 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1545 pNtClose( key32 );
1547 status = pNtDeleteKey( key64 );
1548 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1549 pNtClose( key64 );
1551 pNtDeleteKey( root32 );
1552 pNtClose( root32 );
1553 pNtDeleteKey( root64 );
1554 pNtClose( root64 );
1556 /* Software\Classes is shared/reflected so behavior is different */
1558 pRtlInitUnicodeString( &str, classes64W );
1559 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1560 if (status == STATUS_ACCESS_DENIED)
1562 skip("Not authorized to modify the Classes key\n");
1563 return;
1565 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1567 pRtlInitUnicodeString( &str, classes32W );
1568 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1569 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1571 dw = 64;
1572 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1573 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1574 pNtClose( key64 );
1576 dw = 32;
1577 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1578 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1579 pNtClose( key32 );
1581 pRtlInitUnicodeString( &str, classes64W );
1582 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1583 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1584 len = sizeof(buffer);
1585 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1586 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1587 dw = *(DWORD *)info->Data;
1588 ok( dw == ptr_size, "wrong value %u\n", dw );
1590 pRtlInitUnicodeString( &str, classes32W );
1591 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1592 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1593 len = sizeof(buffer);
1594 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1595 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1596 dw = *(DWORD *)info->Data;
1597 ok( dw == 32, "wrong value %u\n", dw );
1599 pNtDeleteKey( key32 );
1600 pNtClose( key32 );
1601 pNtDeleteKey( key64 );
1602 pNtClose( key64 );
1605 static void test_long_value_name(void)
1607 HANDLE key;
1608 NTSTATUS status, expected;
1609 OBJECT_ATTRIBUTES attr;
1610 UNICODE_STRING ValName;
1611 DWORD i;
1613 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1614 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1615 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1617 ValName.MaximumLength = 0xfffc;
1618 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1619 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1620 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1621 ValName.Buffer[i] = 'a';
1622 ValName.Buffer[i] = 0;
1624 status = pNtDeleteValueKey(key, &ValName);
1625 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1626 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1627 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1628 "NtSetValueKey with long value name returned 0x%08x\n", status);
1629 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1630 status = pNtDeleteValueKey(key, &ValName);
1631 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1633 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1634 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1636 pRtlFreeUnicodeString(&ValName);
1637 pNtClose(key);
1640 static void test_NtQueryKey(void)
1642 HANDLE key, subkey, subkey2;
1643 NTSTATUS status;
1644 OBJECT_ATTRIBUTES attr;
1645 ULONG length, len;
1646 KEY_NAME_INFORMATION *info = NULL;
1647 KEY_CACHED_INFORMATION cached_info;
1648 UNICODE_STRING str;
1649 DWORD dw;
1651 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1652 status = pNtOpenKey(&key, KEY_READ, &attr);
1653 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1655 status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
1656 if (status == STATUS_INVALID_PARAMETER) {
1657 win_skip("KeyNameInformation is not supported\n");
1658 pNtClose(key);
1659 return;
1661 todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1662 info = HeapAlloc(GetProcessHeap(), 0, length);
1664 /* non-zero buffer size, but insufficient */
1665 status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
1666 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
1667 ok(length == len, "got %d, expected %d\n", len, length);
1668 ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
1669 info->NameLength, winetestpath.Length);
1671 /* correct buffer size */
1672 status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
1673 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1674 ok(length == len, "got %d, expected %d\n", len, length);
1676 str.Buffer = info->Name;
1677 str.Length = info->NameLength;
1678 ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1679 "got %s, expected %s\n",
1680 wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1681 wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1683 HeapFree(GetProcessHeap(), 0, info);
1685 attr.RootDirectory = key;
1686 attr.ObjectName = &str;
1687 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1688 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1689 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1691 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1692 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1694 if (status == STATUS_SUCCESS)
1696 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1697 ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1698 ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1699 ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
1700 ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1701 ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1702 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1705 attr.RootDirectory = subkey;
1706 attr.ObjectName = &str;
1707 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
1708 status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
1709 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1711 pRtlCreateUnicodeStringFromAsciiz(&str, "val");
1712 dw = 64;
1713 status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
1714 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1716 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1717 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1719 if (status == STATUS_SUCCESS)
1721 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1722 ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1723 ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1724 ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
1725 ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1726 ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1727 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1730 status = pNtDeleteKey(subkey2);
1731 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1732 status = pNtDeleteKey(subkey);
1733 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1735 pNtClose(subkey2);
1736 pNtClose(subkey);
1737 pNtClose(key);
1740 static void test_notify(void)
1742 OBJECT_ATTRIBUTES attr;
1743 LARGE_INTEGER timeout;
1744 IO_STATUS_BLOCK iosb;
1745 UNICODE_STRING str;
1746 HANDLE key, events[2], subkey;
1747 NTSTATUS status;
1749 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1750 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1751 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1753 events[0] = CreateEventW(NULL, FALSE, TRUE, NULL);
1754 ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError());
1755 events[1] = CreateEventW(NULL, FALSE, TRUE, NULL);
1756 ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError());
1758 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1759 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1760 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1761 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1763 timeout.QuadPart = 0;
1764 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1765 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1766 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1767 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1769 attr.RootDirectory = key;
1770 attr.ObjectName = &str;
1772 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1773 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1774 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1776 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1777 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1778 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1779 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1781 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1782 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1783 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1784 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1786 status = pNtDeleteKey(subkey);
1787 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1789 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1790 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1791 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1792 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1794 pNtClose(subkey);
1796 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1797 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1798 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1799 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1801 pNtClose(key);
1803 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1804 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1805 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1806 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1808 if (pNtNotifyChangeMultipleKeys)
1810 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1811 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1812 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1814 status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1815 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1817 timeout.QuadPart = 0;
1818 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1819 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1821 attr.RootDirectory = key;
1822 attr.ObjectName = &str;
1823 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1824 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1825 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1827 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1828 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1830 status = pNtDeleteKey(subkey);
1831 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1832 pNtClose(subkey);
1833 pNtClose(key);
1835 else
1837 win_skip("NtNotifyChangeMultipleKeys not available\n");
1840 pNtClose(events[0]);
1841 pNtClose(events[1]);
1844 START_TEST(reg)
1846 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1847 if(!InitFunctionPtrs())
1848 return;
1849 pRtlFormatCurrentUserKeyPath(&winetestpath);
1850 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1851 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1852 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1854 pRtlAppendUnicodeToString(&winetestpath, winetest);
1856 test_NtCreateKey();
1857 test_NtOpenKey();
1858 test_NtSetValueKey();
1859 test_RtlCheckRegistryKey();
1860 test_RtlOpenCurrentUser();
1861 test_RtlQueryRegistryValues();
1862 test_RtlpNtQueryValueKey();
1863 test_NtFlushKey();
1864 test_NtQueryKey();
1865 test_NtQueryLicenseKey();
1866 test_NtQueryValueKey();
1867 test_long_value_name();
1868 test_notify();
1869 test_NtDeleteKey();
1870 test_symlinks();
1871 test_redirection();
1873 pRtlFreeUnicodeString(&winetestpath);
1875 FreeLibrary(hntdll);