ntdll/tests: Dump entire VM_COUNTERS structure.
[wine.git] / dlls / ntdll / tests / reg.c
blob7d2e56644c80594e44b90e6cabd4b4f0dc382235
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 /* Zero accessmask */
366 attr.Length = sizeof(attr);
367 key = (HANDLE)0xdeadbeef;
368 status = pNtOpenKey(&key, 0, &attr);
369 todo_wine
370 ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
371 todo_wine
372 ok(!key, "key = %p\n", key);
373 if (status == STATUS_SUCCESS) NtClose(key);
375 /* Calling without parent key requres full registry path. */
376 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
377 InitializeObjectAttributes(&attr, &str, 0, 0, 0);
378 key = (HANDLE)0xdeadbeef;
379 status = pNtOpenKey(&key, KEY_READ, &attr);
380 todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
381 todo_wine
382 ok(!key, "key = %p\n", key);
383 pRtlFreeUnicodeString( &str );
385 /* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
386 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine" );
387 status = pNtOpenKey(&key, KEY_READ, &attr);
388 todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey Failed: 0x%08x\n", status);
390 attr.Attributes = OBJ_CASE_INSENSITIVE;
391 status = pNtOpenKey(&key, KEY_READ, &attr);
392 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
393 pNtClose(key);
394 pRtlFreeUnicodeString( &str );
396 pRtlCreateUnicodeStringFromAsciiz( &str, "" );
397 status = pNtOpenKey(&key, KEY_READ, &attr);
398 todo_wine
399 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
400 pRtlFreeUnicodeString( &str );
402 pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
403 status = pNtOpenKey(&key, KEY_READ, &attr);
404 todo_wine
405 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
406 pRtlFreeUnicodeString( &str );
408 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
409 status = pNtOpenKey(&key, KEY_READ, &attr);
410 todo_wine
411 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
412 pNtClose( key );
413 pRtlFreeUnicodeString( &str );
415 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
416 status = pNtOpenKey(&key, KEY_READ, &attr);
417 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
418 pNtClose( key );
419 pRtlFreeUnicodeString( &str );
421 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
422 status = pNtOpenKey(&key, KEY_READ, &attr);
423 todo_wine
424 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
425 pRtlFreeUnicodeString( &str );
427 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
428 status = pNtOpenKey(&key, KEY_READ, &attr);
429 todo_wine
430 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
431 pRtlFreeUnicodeString( &str );
433 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
434 status = pNtOpenKey(&key, KEY_READ, &attr);
435 todo_wine
436 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
437 pRtlFreeUnicodeString( &str );
439 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
440 status = pNtOpenKey(&key, KEY_READ, &attr);
441 todo_wine
442 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
443 pRtlFreeUnicodeString( &str );
445 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
446 status = pNtOpenKey(&key, KEY_READ, &attr);
447 todo_wine
448 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
449 pRtlFreeUnicodeString( &str );
451 if (!pNtOpenKeyEx)
453 win_skip("NtOpenKeyEx not available\n");
454 return;
457 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
458 status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0);
459 ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status);
461 pNtClose(key);
464 static void test_NtCreateKey(void)
466 /*Create WineTest*/
467 OBJECT_ATTRIBUTES attr;
468 HANDLE key, subkey;
469 ACCESS_MASK am = GENERIC_ALL;
470 NTSTATUS status;
471 UNICODE_STRING str;
473 /* All NULL */
474 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
475 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
476 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
478 /* Only the key */
479 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
480 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
481 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
483 /* Only accessmask */
484 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
485 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
486 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
488 /* Key and accessmask */
489 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
490 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
491 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
493 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
495 /* Only attributes */
496 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
497 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
498 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
500 /* Length > sizeof(OBJECT_ATTRIBUTES) */
501 attr.Length *= 2;
502 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
503 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
505 attr.Length = sizeof(attr);
506 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
507 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
509 attr.RootDirectory = key;
510 attr.ObjectName = &str;
512 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
513 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
514 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
515 pRtlFreeUnicodeString( &str );
517 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
518 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
519 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
520 pRtlFreeUnicodeString( &str );
522 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
523 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
524 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
525 pRtlFreeUnicodeString( &str );
527 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
528 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
529 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
530 "NtCreateKey failed: 0x%08x\n", status );
531 if (status == STATUS_SUCCESS)
533 pNtDeleteKey( subkey );
534 pNtClose( subkey );
536 pRtlFreeUnicodeString( &str );
538 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
539 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
540 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
541 pRtlFreeUnicodeString( &str );
542 pNtDeleteKey( subkey );
543 pNtClose( subkey );
545 attr.RootDirectory = 0;
546 attr.Attributes = OBJ_CASE_INSENSITIVE;
548 pRtlCreateUnicodeStringFromAsciiz( &str, "" );
549 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
550 todo_wine
551 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
552 pRtlFreeUnicodeString( &str );
554 pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
555 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
556 todo_wine
557 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
558 pRtlFreeUnicodeString( &str );
560 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
561 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
562 todo_wine
563 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
564 "NtCreateKey failed: 0x%08x\n", status );
565 if (!status) pNtClose( subkey );
566 pRtlFreeUnicodeString( &str );
568 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
569 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
570 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
571 "NtCreateKey failed: 0x%08x\n", status );
572 if (!status) pNtClose( subkey );
573 pRtlFreeUnicodeString( &str );
575 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
576 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
577 todo_wine
578 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
579 pRtlFreeUnicodeString( &str );
581 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
582 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
583 todo_wine
584 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
585 pRtlFreeUnicodeString( &str );
587 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
588 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
589 todo_wine
590 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
591 pRtlFreeUnicodeString( &str );
593 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
594 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
595 todo_wine
596 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
597 pRtlFreeUnicodeString( &str );
599 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
600 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
601 todo_wine
602 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
603 pRtlFreeUnicodeString( &str );
605 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
606 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
607 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
608 "NtCreateKey failed: 0x%08x\n", status );
609 if (!status) pNtClose( subkey );
610 pRtlFreeUnicodeString( &str );
612 /* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */
613 attr.Attributes = 0;
614 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
615 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
616 todo_wine
617 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
618 pRtlFreeUnicodeString( &str );
620 pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\Machine\\Software\\Classes" );
621 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
622 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
623 "NtCreateKey failed: 0x%08x\n", status );
624 if (!status) pNtClose( subkey );
625 pRtlFreeUnicodeString( &str );
627 pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" );
628 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
629 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
630 "NtCreateKey failed: 0x%08x\n", status );
631 if (!status) pNtClose( subkey );
632 pRtlFreeUnicodeString( &str );
634 pNtClose(key);
637 static void test_NtSetValueKey(void)
639 HANDLE key;
640 NTSTATUS status;
641 OBJECT_ATTRIBUTES attr;
642 ACCESS_MASK am = KEY_WRITE;
643 UNICODE_STRING ValName;
644 DWORD data = 711;
646 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
647 status = pNtOpenKey(&key, am, &attr);
648 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
650 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
651 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
652 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
653 pRtlFreeUnicodeString(&ValName);
655 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
656 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
657 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
658 pRtlFreeUnicodeString(&ValName);
660 pNtClose(key);
663 static void test_RtlOpenCurrentUser(void)
665 NTSTATUS status;
666 HANDLE handle;
667 status=pRtlOpenCurrentUser(KEY_READ, &handle);
668 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
669 pNtClose(handle);
672 static void test_RtlCheckRegistryKey(void)
674 NTSTATUS status;
676 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
677 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
679 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
680 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
683 static void test_NtFlushKey(void)
685 NTSTATUS status;
686 HANDLE hkey;
687 OBJECT_ATTRIBUTES attr;
688 ACCESS_MASK am = KEY_ALL_ACCESS;
690 status = pNtFlushKey(NULL);
691 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
693 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
694 pNtOpenKey(&hkey, am, &attr);
696 status = pNtFlushKey(hkey);
697 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
699 pNtClose(hkey);
702 static void test_NtQueryValueKey(void)
704 HANDLE key;
705 NTSTATUS status;
706 OBJECT_ATTRIBUTES attr;
707 UNICODE_STRING ValName;
708 KEY_VALUE_BASIC_INFORMATION *basic_info;
709 KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi;
710 KEY_VALUE_FULL_INFORMATION *full_info;
711 DWORD len, expected;
713 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
715 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
716 status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr);
717 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
719 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
720 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
721 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
722 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
723 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
724 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
725 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
726 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
728 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
729 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
730 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
731 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
732 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
733 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
734 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
735 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
736 HeapFree(GetProcessHeap(), 0, basic_info);
738 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
739 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
740 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
741 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
742 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
743 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
744 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
745 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
747 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
748 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
749 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
750 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
751 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
752 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
753 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
754 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
755 HeapFree(GetProcessHeap(), 0, partial_info);
757 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
758 full_info = HeapAlloc(GetProcessHeap(), 0, len);
759 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
760 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
761 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
762 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
763 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
764 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
765 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
766 "NtQueryValueKey returned wrong len %d\n", len);
767 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
769 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
770 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
771 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
772 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
773 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
774 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
775 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
776 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
777 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
778 *(DWORD *)((char *)full_info + full_info->DataOffset));
779 HeapFree(GetProcessHeap(), 0, full_info);
781 pRtlFreeUnicodeString(&ValName);
782 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
784 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
785 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
786 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
787 memset(partial_info, 0xbd, len+1);
788 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
789 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
790 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
791 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
792 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
793 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
794 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
796 expected = len;
797 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
798 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
799 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
800 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
801 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
802 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
803 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
804 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
805 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
806 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
807 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
808 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
810 HeapFree(GetProcessHeap(), 0, partial_info);
811 pRtlFreeUnicodeString(&ValName);
813 pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest");
814 status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0);
815 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
817 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
818 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
819 ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type);
820 ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength);
821 pRtlFreeUnicodeString(&ValName);
823 pNtClose(key);
826 static void test_NtDeleteKey(void)
828 NTSTATUS status;
829 HANDLE hkey;
830 OBJECT_ATTRIBUTES attr;
831 ACCESS_MASK am = KEY_ALL_ACCESS;
833 status = pNtDeleteKey(NULL);
834 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
836 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
837 status = pNtOpenKey(&hkey, am, &attr);
838 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
840 status = pNtDeleteKey(hkey);
841 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
844 static void test_NtQueryLicenseKey(void)
846 static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
847 UNICODE_STRING name;
848 WORD buffer[32];
849 NTSTATUS status;
850 ULONG type, len;
851 DWORD value;
853 if (!pNtQueryLicenseValue)
855 win_skip("NtQueryLicenseValue not found, skipping tests\n");
856 return;
859 type = 0xdead;
860 len = 0xbeef;
861 memset(&name, 0, sizeof(name));
862 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
863 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
864 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
865 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
867 /* test with empty key */
868 pRtlCreateUnicodeStringFromAsciiz(&name, "");
870 type = 0xdead;
871 len = 0xbeef;
872 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
873 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
874 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
875 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
877 type = 0xdead;
878 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
879 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
880 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
882 len = 0xbeef;
883 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
884 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
885 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
887 type = 0xdead;
888 len = 0xbeef;
889 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
890 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
891 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
892 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
894 pRtlFreeUnicodeString(&name);
896 /* test with nonexistent licence key */
897 pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
899 type = 0xdead;
900 len = 0xbeef;
901 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
902 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
903 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
904 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
906 type = 0xdead;
907 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
908 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
909 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
911 len = 0xbeef;
912 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
913 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
914 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
916 type = 0xdead;
917 len = 0xbeef;
918 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
919 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n");
920 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
921 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
923 pRtlFreeUnicodeString(&name);
925 /* test with REG_SZ license key */
926 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
928 type = 0xdead;
929 len = 0xbeef;
930 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
931 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
932 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
933 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
935 type = 0xdead;
936 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
937 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
938 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
940 type = 0xdead;
941 len = 0;
942 status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
943 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\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);
947 len = 0;
948 status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
949 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
950 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
952 type = 0xdead;
953 len = 0;
954 memset(buffer, 0x11, sizeof(buffer));
955 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
956 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
957 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
958 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
959 ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
961 type = 0xdead;
962 len = 0;
963 memset(buffer, 0x11, sizeof(buffer));
964 status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
965 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
966 ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
967 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
968 ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
970 pRtlFreeUnicodeString(&name);
972 /* test with REG_DWORD license key */
973 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
975 type = 0xdead;
976 len = 0xbeef;
977 status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
978 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
979 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
980 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
982 type = 0xdead;
983 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
984 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
985 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
987 type = 0xdead;
988 len = 0;
989 status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
990 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\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);
994 len = 0;
995 status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
996 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
997 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
999 type = 0xdead;
1000 len = 0;
1001 value = 0xdeadbeef;
1002 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
1003 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
1004 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
1005 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1006 ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
1008 type = 0xdead;
1009 len = 0;
1010 status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
1011 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
1012 ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
1013 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1015 pRtlFreeUnicodeString(&name);
1018 static void test_RtlpNtQueryValueKey(void)
1020 NTSTATUS status;
1022 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
1023 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
1026 static void test_symlinks(void)
1028 static const WCHAR linkW[] = {'l','i','n','k',0};
1029 static const WCHAR valueW[] = {'v','a','l','u','e',0};
1030 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
1031 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
1032 static UNICODE_STRING null_str;
1033 char buffer[1024];
1034 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1035 WCHAR *target;
1036 UNICODE_STRING symlink_str, link_str, target_str, value_str;
1037 HANDLE root, key, link;
1038 OBJECT_ATTRIBUTES attr;
1039 NTSTATUS status;
1040 DWORD target_len, len, dw;
1042 pRtlInitUnicodeString( &link_str, linkW );
1043 pRtlInitUnicodeString( &symlink_str, symlinkW );
1044 pRtlInitUnicodeString( &target_str, targetW + 1 );
1045 pRtlInitUnicodeString( &value_str, valueW );
1047 target_len = winetestpath.Length + sizeof(targetW);
1048 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
1049 memcpy( target, winetestpath.Buffer, winetestpath.Length );
1050 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
1052 attr.Length = sizeof(attr);
1053 attr.RootDirectory = 0;
1054 attr.Attributes = 0;
1055 attr.ObjectName = &winetestpath;
1056 attr.SecurityDescriptor = NULL;
1057 attr.SecurityQualityOfService = NULL;
1059 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1060 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1062 attr.RootDirectory = root;
1063 attr.ObjectName = &link_str;
1064 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1065 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1067 /* REG_SZ is not allowed */
1068 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
1069 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1070 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1071 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1072 /* other values are not allowed */
1073 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1074 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1076 /* try opening the target through the link */
1078 attr.ObjectName = &link_str;
1079 key = (HANDLE)0xdeadbeef;
1080 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1081 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1082 ok( !key, "key = %p\n", key );
1084 attr.ObjectName = &target_str;
1085 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1086 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1088 dw = 0xbeef;
1089 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1090 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1091 pNtClose( key );
1093 attr.ObjectName = &link_str;
1094 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1095 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1097 len = sizeof(buffer);
1098 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1099 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1100 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1102 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1103 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1105 /* REG_LINK can be created in non-link keys */
1106 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1107 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1108 len = sizeof(buffer);
1109 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1110 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1111 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1112 "wrong len %u\n", len );
1113 status = pNtDeleteValueKey( key, &symlink_str );
1114 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
1116 pNtClose( key );
1118 attr.Attributes = 0;
1119 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1120 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1122 len = sizeof(buffer);
1123 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1124 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1125 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1127 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1128 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1129 pNtClose( key );
1131 /* now open the symlink itself */
1133 attr.RootDirectory = root;
1134 attr.Attributes = OBJ_OPENLINK;
1135 attr.ObjectName = &link_str;
1136 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1137 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1139 len = sizeof(buffer);
1140 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1141 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1142 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1143 "wrong len %u\n", len );
1144 pNtClose( key );
1146 if (pNtOpenKeyEx)
1148 /* REG_OPTION_OPEN_LINK flag doesn't matter */
1149 status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
1150 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1152 len = sizeof(buffer);
1153 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1154 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1155 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1156 "wrong len %u\n", len );
1157 pNtClose( key );
1159 status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 );
1160 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1162 len = sizeof(buffer);
1163 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1164 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1165 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1166 "wrong len %u\n", len );
1167 pNtClose( key );
1169 attr.Attributes = 0;
1170 status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
1171 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 );
1179 attr.Attributes = OBJ_OPENLINK;
1180 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1181 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1182 len = sizeof(buffer);
1183 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1184 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1185 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1186 "wrong len %u\n", len );
1187 pNtClose( key );
1189 /* delete target and create by NtCreateKey on link */
1190 attr.ObjectName = &target_str;
1191 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1192 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1193 status = pNtDeleteKey( key );
1194 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1195 pNtClose( key );
1197 attr.ObjectName = &link_str;
1198 attr.Attributes = 0;
1199 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1200 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1202 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1203 todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1204 pNtClose( key );
1205 if (status) /* can be removed once todo_wine above is fixed */
1207 attr.ObjectName = &target_str;
1208 attr.Attributes = OBJ_OPENLINK;
1209 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1210 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1211 pNtClose( key );
1214 attr.ObjectName = &target_str;
1215 attr.Attributes = OBJ_OPENLINK;
1216 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1217 ok( status == STATUS_SUCCESS, "NtOpenKey wrong status 0x%08x\n", status );
1219 if (0) /* crashes the Windows kernel on some Vista systems */
1221 /* reopen the link from itself */
1223 attr.RootDirectory = link;
1224 attr.Attributes = OBJ_OPENLINK;
1225 attr.ObjectName = &null_str;
1226 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1227 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1228 len = sizeof(buffer);
1229 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1230 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1231 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1232 "wrong len %u\n", len );
1233 pNtClose( key );
1235 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1236 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1237 len = sizeof(buffer);
1238 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1239 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1240 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1241 "wrong len %u\n", len );
1242 pNtClose( key );
1245 if (0) /* crashes the Windows kernel in most versions */
1247 attr.RootDirectory = link;
1248 attr.Attributes = 0;
1249 attr.ObjectName = &null_str;
1250 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1251 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1252 len = sizeof(buffer);
1253 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1254 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1255 pNtClose( key );
1257 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1258 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1259 len = sizeof(buffer);
1260 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1261 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1262 pNtClose( key );
1265 /* target with terminating null doesn't work */
1266 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
1267 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1268 attr.RootDirectory = root;
1269 attr.Attributes = 0;
1270 attr.ObjectName = &link_str;
1271 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1272 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1274 /* relative symlink, works only on win2k */
1275 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
1276 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1277 attr.ObjectName = &link_str;
1278 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1279 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
1280 "NtOpenKey wrong status 0x%08x\n", status );
1282 key = (HKEY)0xdeadbeef;
1283 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, NULL );
1284 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
1285 ok( !key, "key = %p\n", key );
1287 status = pNtDeleteKey( link );
1288 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1289 pNtClose( link );
1291 attr.ObjectName = &target_str;
1292 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1293 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1294 status = pNtDeleteKey( key );
1295 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1296 pNtClose( key );
1298 /* symlink loop */
1300 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1301 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1302 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
1303 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
1304 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
1305 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1307 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1308 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
1309 "NtOpenKey failed: 0x%08x\n", status );
1311 attr.Attributes = OBJ_OPENLINK;
1312 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1313 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1314 pNtClose( key );
1316 status = pNtDeleteKey( link );
1317 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1318 pNtClose( link );
1320 status = pNtDeleteKey( root );
1321 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1322 pNtClose( root );
1324 pRtlFreeHeap(GetProcessHeap(), 0, target);
1327 static WCHAR valueW[] = {'v','a','l','u','e'};
1328 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
1329 static const DWORD ptr_size = 8 * sizeof(void*);
1331 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
1333 char tmp[32];
1334 NTSTATUS status;
1335 OBJECT_ATTRIBUTES attr;
1336 UNICODE_STRING str;
1337 HANDLE key;
1338 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
1339 DWORD dw, len = sizeof(tmp);
1341 attr.Length = sizeof(attr);
1342 attr.RootDirectory = root;
1343 attr.Attributes = OBJ_CASE_INSENSITIVE;
1344 attr.ObjectName = &str;
1345 attr.SecurityDescriptor = NULL;
1346 attr.SecurityQualityOfService = NULL;
1347 pRtlCreateUnicodeStringFromAsciiz( &str, name );
1349 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1350 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
1351 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
1353 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1354 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1355 dw = 0;
1356 else
1358 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
1359 dw = *(DWORD *)info->Data;
1361 pNtClose( key );
1362 pRtlFreeUnicodeString( &str );
1363 return dw;
1366 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
1368 DWORD dw = get_key_value( root, name, flags );
1369 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
1371 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
1373 static void test_redirection(void)
1375 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1376 'M','a','c','h','i','n','e','\\',
1377 'S','o','f','t','w','a','r','e',0};
1378 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1379 'M','a','c','h','i','n','e','\\',
1380 'S','o','f','t','w','a','r','e','\\',
1381 'W','o','w','6','4','3','2','N','o','d','e',0};
1382 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1383 'M','a','c','h','i','n','e','\\',
1384 'S','o','f','t','w','a','r','e','\\',
1385 'W','i','n','e',0};
1386 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1387 'M','a','c','h','i','n','e','\\',
1388 'S','o','f','t','w','a','r','e','\\',
1389 'W','o','w','6','4','3','2','N','o','d','e','\\',
1390 'W','i','n','e',0};
1391 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1392 'M','a','c','h','i','n','e','\\',
1393 'S','o','f','t','w','a','r','e','\\',
1394 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
1395 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1396 'M','a','c','h','i','n','e','\\',
1397 'S','o','f','t','w','a','r','e','\\',
1398 'W','o','w','6','4','3','2','N','o','d','e','\\',
1399 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
1400 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1401 'M','a','c','h','i','n','e','\\',
1402 'S','o','f','t','w','a','r','e','\\',
1403 'C','l','a','s','s','e','s','\\',
1404 'W','i','n','e',0};
1405 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1406 'M','a','c','h','i','n','e','\\',
1407 'S','o','f','t','w','a','r','e','\\',
1408 'C','l','a','s','s','e','s','\\',
1409 'W','o','w','6','4','3','2','N','o','d','e','\\',
1410 'W','i','n','e',0};
1411 NTSTATUS status;
1412 OBJECT_ATTRIBUTES attr;
1413 UNICODE_STRING str;
1414 char buffer[1024];
1415 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1416 DWORD dw, len;
1417 HANDLE key, root32, root64, key32, key64;
1418 BOOL is_vista = FALSE;
1420 if (ptr_size != 64)
1422 ULONG is_wow64, len;
1423 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
1424 &is_wow64, sizeof(is_wow64), &len ) ||
1425 !is_wow64)
1427 trace( "Not on Wow64, no redirection\n" );
1428 return;
1432 attr.Length = sizeof(attr);
1433 attr.RootDirectory = 0;
1434 attr.Attributes = OBJ_CASE_INSENSITIVE;
1435 attr.ObjectName = &str;
1436 attr.SecurityDescriptor = NULL;
1437 attr.SecurityQualityOfService = NULL;
1439 pRtlInitUnicodeString( &str, wine64W );
1440 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1441 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1443 pRtlInitUnicodeString( &str, wine32W );
1444 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1445 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1447 pRtlInitUnicodeString( &str, key64W );
1448 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1449 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1451 pRtlInitUnicodeString( &str, key32W );
1452 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1453 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1455 dw = 64;
1456 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1457 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1459 dw = 32;
1460 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1461 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1463 len = sizeof(buffer);
1464 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1465 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1466 dw = *(DWORD *)info->Data;
1467 ok( dw == 32, "wrong value %u\n", dw );
1469 len = sizeof(buffer);
1470 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1471 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1472 dw = *(DWORD *)info->Data;
1473 ok( dw == 64, "wrong value %u\n", dw );
1475 pRtlInitUnicodeString( &str, softwareW );
1476 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1477 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1479 if (ptr_size == 32)
1481 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1482 /* the new (and simpler) Win7 mechanism doesn't */
1483 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1485 trace( "using Vista-style Wow6432Node handling\n" );
1486 is_vista = TRUE;
1488 check_key_value( key, "Wine\\Winetest", 0, 32 );
1489 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1490 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1491 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1492 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1493 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1495 else
1497 check_key_value( key, "Wine\\Winetest", 0, 64 );
1498 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1500 pNtClose( key );
1502 if (ptr_size == 32)
1504 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1505 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1506 dw = get_key_value( key, "Wine\\Winetest", 0 );
1507 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1508 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1509 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1510 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1511 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1512 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1513 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1514 pNtClose( key );
1516 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1517 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1518 check_key_value( key, "Wine\\Winetest", 0, 32 );
1519 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1520 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1521 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1522 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1523 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1524 pNtClose( key );
1527 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1528 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1529 if (ptr_size == 64)
1531 /* KEY_WOW64 flags have no effect on 64-bit */
1532 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1533 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1534 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1535 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1537 else
1539 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1540 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1541 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1542 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1545 pRtlInitUnicodeString( &str, wownodeW );
1546 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1547 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1548 check_key_value( key, "Wine\\Winetest", 0, 32 );
1549 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1550 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1551 pNtClose( key );
1553 if (ptr_size == 32)
1555 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1556 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1557 dw = get_key_value( key, "Wine\\Winetest", 0 );
1558 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1559 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1560 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1561 pNtClose( key );
1563 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1564 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1565 check_key_value( key, "Wine\\Winetest", 0, 32 );
1566 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1567 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1568 pNtClose( key );
1571 pRtlInitUnicodeString( &str, wine32W );
1572 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1573 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1574 check_key_value( key, "Winetest", 0, 32 );
1575 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1576 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1577 pNtClose( key );
1579 if (ptr_size == 32)
1581 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1582 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1583 dw = get_key_value( key, "Winetest", 0 );
1584 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1585 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1586 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1587 pNtClose( key );
1589 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1590 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1591 check_key_value( key, "Winetest", 0, 32 );
1592 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1593 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1594 pNtClose( key );
1597 pRtlInitUnicodeString( &str, wine64W );
1598 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1599 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1600 check_key_value( key, "Winetest", 0, ptr_size );
1601 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1602 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1603 pNtClose( key );
1605 if (ptr_size == 32)
1607 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1608 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1609 dw = get_key_value( key, "Winetest", 0 );
1610 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1611 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1612 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1613 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1614 pNtClose( key );
1616 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1617 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1618 check_key_value( key, "Winetest", 0, 32 );
1619 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1620 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1621 pNtClose( key );
1624 status = pNtDeleteKey( key32 );
1625 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1626 pNtClose( key32 );
1628 status = pNtDeleteKey( key64 );
1629 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1630 pNtClose( key64 );
1632 pNtDeleteKey( root32 );
1633 pNtClose( root32 );
1634 pNtDeleteKey( root64 );
1635 pNtClose( root64 );
1637 /* Software\Classes is shared/reflected so behavior is different */
1639 pRtlInitUnicodeString( &str, classes64W );
1640 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1641 if (status == STATUS_ACCESS_DENIED)
1643 skip("Not authorized to modify the Classes key\n");
1644 return;
1646 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1648 pRtlInitUnicodeString( &str, classes32W );
1649 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1650 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1652 dw = 64;
1653 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1654 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1655 pNtClose( key64 );
1657 dw = 32;
1658 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1659 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1660 pNtClose( key32 );
1662 pRtlInitUnicodeString( &str, classes64W );
1663 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1664 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1665 len = sizeof(buffer);
1666 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1667 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1668 dw = *(DWORD *)info->Data;
1669 ok( dw == ptr_size, "wrong value %u\n", dw );
1671 pRtlInitUnicodeString( &str, classes32W );
1672 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1673 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1674 len = sizeof(buffer);
1675 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1676 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1677 dw = *(DWORD *)info->Data;
1678 ok( dw == 32, "wrong value %u\n", dw );
1680 pNtDeleteKey( key32 );
1681 pNtClose( key32 );
1682 pNtDeleteKey( key64 );
1683 pNtClose( key64 );
1686 static void test_long_value_name(void)
1688 HANDLE key;
1689 NTSTATUS status, expected;
1690 OBJECT_ATTRIBUTES attr;
1691 UNICODE_STRING ValName;
1692 DWORD i;
1694 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1695 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1696 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1698 ValName.MaximumLength = 0xfffc;
1699 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1700 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1701 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1702 ValName.Buffer[i] = 'a';
1703 ValName.Buffer[i] = 0;
1705 status = pNtDeleteValueKey(key, &ValName);
1706 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1707 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1708 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1709 "NtSetValueKey with long value name returned 0x%08x\n", status);
1710 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1711 status = pNtDeleteValueKey(key, &ValName);
1712 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1714 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1715 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1717 pRtlFreeUnicodeString(&ValName);
1718 pNtClose(key);
1721 static void test_NtQueryKey(void)
1723 HANDLE key, subkey, subkey2;
1724 NTSTATUS status;
1725 OBJECT_ATTRIBUTES attr;
1726 ULONG length, len;
1727 KEY_NAME_INFORMATION *info = NULL;
1728 KEY_CACHED_INFORMATION cached_info;
1729 UNICODE_STRING str;
1730 DWORD dw;
1732 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1733 status = pNtOpenKey(&key, KEY_READ, &attr);
1734 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1736 status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
1737 if (status == STATUS_INVALID_PARAMETER) {
1738 win_skip("KeyNameInformation is not supported\n");
1739 pNtClose(key);
1740 return;
1742 todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1743 info = HeapAlloc(GetProcessHeap(), 0, length);
1745 /* non-zero buffer size, but insufficient */
1746 status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
1747 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
1748 ok(length == len, "got %d, expected %d\n", len, length);
1749 ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
1750 info->NameLength, winetestpath.Length);
1752 /* correct buffer size */
1753 status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
1754 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1755 ok(length == len, "got %d, expected %d\n", len, length);
1757 str.Buffer = info->Name;
1758 str.Length = info->NameLength;
1759 ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1760 "got %s, expected %s\n",
1761 wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1762 wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1764 HeapFree(GetProcessHeap(), 0, info);
1766 attr.RootDirectory = key;
1767 attr.ObjectName = &str;
1768 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1769 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1770 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1771 pRtlFreeUnicodeString(&str);
1773 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1774 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1776 if (status == STATUS_SUCCESS)
1778 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1779 ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1780 ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1781 ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
1782 ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1783 ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1784 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1787 attr.RootDirectory = subkey;
1788 attr.ObjectName = &str;
1789 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
1790 status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
1791 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1792 pRtlFreeUnicodeString(&str);
1794 pRtlCreateUnicodeStringFromAsciiz(&str, "val");
1795 dw = 64;
1796 status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
1797 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1798 pRtlFreeUnicodeString(&str);
1800 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1801 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1803 if (status == STATUS_SUCCESS)
1805 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1806 ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1807 ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1808 ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
1809 ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1810 ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1811 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1814 status = pNtDeleteKey(subkey2);
1815 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1816 status = pNtDeleteKey(subkey);
1817 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1819 pNtClose(subkey2);
1820 pNtClose(subkey);
1821 pNtClose(key);
1824 static void test_notify(void)
1826 OBJECT_ATTRIBUTES attr;
1827 LARGE_INTEGER timeout;
1828 IO_STATUS_BLOCK iosb;
1829 UNICODE_STRING str;
1830 HANDLE key, events[2], subkey;
1831 NTSTATUS status;
1833 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1834 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1835 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1837 events[0] = CreateEventW(NULL, FALSE, TRUE, NULL);
1838 ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError());
1839 events[1] = CreateEventW(NULL, FALSE, TRUE, NULL);
1840 ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError());
1842 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1843 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1844 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1845 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1847 timeout.QuadPart = 0;
1848 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1849 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1850 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1851 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1853 attr.RootDirectory = key;
1854 attr.ObjectName = &str;
1856 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1857 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1858 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1859 pRtlFreeUnicodeString(&str);
1861 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1862 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1863 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1864 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1866 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1867 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1868 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1869 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1871 status = pNtDeleteKey(subkey);
1872 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1874 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1875 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1876 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1877 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1879 pNtClose(subkey);
1881 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1882 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1883 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1884 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1886 pNtClose(key);
1888 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1889 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1890 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1891 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1893 if (pNtNotifyChangeMultipleKeys)
1895 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1896 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1897 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1899 status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1900 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1902 timeout.QuadPart = 0;
1903 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1904 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1906 attr.RootDirectory = key;
1907 attr.ObjectName = &str;
1908 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1909 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1910 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1911 pRtlFreeUnicodeString(&str);
1913 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1914 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1916 status = pNtDeleteKey(subkey);
1917 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1918 pNtClose(subkey);
1919 pNtClose(key);
1921 else
1923 win_skip("NtNotifyChangeMultipleKeys not available\n");
1926 pNtClose(events[0]);
1927 pNtClose(events[1]);
1930 START_TEST(reg)
1932 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1933 if(!InitFunctionPtrs())
1934 return;
1935 pRtlFormatCurrentUserKeyPath(&winetestpath);
1936 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1937 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1938 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1940 pRtlAppendUnicodeToString(&winetestpath, winetest);
1942 test_NtCreateKey();
1943 test_NtOpenKey();
1944 test_NtSetValueKey();
1945 test_RtlCheckRegistryKey();
1946 test_RtlOpenCurrentUser();
1947 test_RtlQueryRegistryValues();
1948 test_RtlpNtQueryValueKey();
1949 test_NtFlushKey();
1950 test_NtQueryKey();
1951 test_NtQueryLicenseKey();
1952 test_NtQueryValueKey();
1953 test_long_value_name();
1954 test_notify();
1955 test_NtDeleteKey();
1956 test_symlinks();
1957 test_redirection();
1959 pRtlFreeUnicodeString(&winetestpath);
1961 FreeLibrary(hntdll);