ntdll/tests: Add tests for RtlCreateRegistryKey.
[wine.git] / dlls / ntdll / tests / reg.c
blob79344e7e74253b7bbfb88892b3082ec5837a7b8e
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 * pRtlCreateRegistryKey)(ULONG, PWSTR);
149 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
150 static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN);
151 static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE,
152 void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN);
153 static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*);
155 static HMODULE hntdll = 0;
156 static int CurrentTest = 0;
157 static UNICODE_STRING winetestpath;
159 #define NTDLL_GET_PROC(func) \
160 p ## func = (void*)GetProcAddress(hntdll, #func); \
161 if(!p ## func) { \
162 trace("GetProcAddress(%s) failed\n", #func); \
163 FreeLibrary(hntdll); \
164 return FALSE; \
167 static BOOL InitFunctionPtrs(void)
169 hntdll = LoadLibraryA("ntdll.dll");
170 if(!hntdll) {
171 trace("Could not load ntdll.dll\n");
172 return FALSE;
174 NTDLL_GET_PROC(RtlInitUnicodeString)
175 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
176 NTDLL_GET_PROC(RtlCreateUnicodeString)
177 NTDLL_GET_PROC(RtlFreeUnicodeString)
178 NTDLL_GET_PROC(RtlQueryRegistryValues)
179 NTDLL_GET_PROC(RtlCheckRegistryKey)
180 NTDLL_GET_PROC(RtlOpenCurrentUser)
181 NTDLL_GET_PROC(NtClose)
182 NTDLL_GET_PROC(NtDeleteValueKey)
183 NTDLL_GET_PROC(NtCreateKey)
184 NTDLL_GET_PROC(NtFlushKey)
185 NTDLL_GET_PROC(NtDeleteKey)
186 NTDLL_GET_PROC(NtQueryKey)
187 NTDLL_GET_PROC(NtQueryValueKey)
188 NTDLL_GET_PROC(NtQueryInformationProcess)
189 NTDLL_GET_PROC(NtSetValueKey)
190 NTDLL_GET_PROC(NtOpenKey)
191 NTDLL_GET_PROC(NtNotifyChangeKey)
192 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
193 NTDLL_GET_PROC(RtlCompareUnicodeString)
194 NTDLL_GET_PROC(RtlReAllocateHeap)
195 NTDLL_GET_PROC(RtlAppendUnicodeToString)
196 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
197 NTDLL_GET_PROC(RtlFreeHeap)
198 NTDLL_GET_PROC(RtlAllocateHeap)
199 NTDLL_GET_PROC(RtlZeroMemory)
200 NTDLL_GET_PROC(RtlCreateRegistryKey)
201 NTDLL_GET_PROC(RtlpNtQueryValueKey)
202 NTDLL_GET_PROC(RtlOpenCurrentUser)
203 NTDLL_GET_PROC(NtWaitForSingleObject)
205 /* optional functions */
206 pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue");
207 pNtOpenKeyEx = (void *)GetProcAddress(hntdll, "NtOpenKeyEx");
208 pNtNotifyChangeMultipleKeys = (void *)GetProcAddress(hntdll, "NtNotifyChangeMultipleKeys");
210 return TRUE;
212 #undef NTDLL_GET_PROC
214 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
215 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
217 NTSTATUS ret = STATUS_SUCCESS;
219 trace("**Test %d**\n", CurrentTest);
220 trace("ValueName: %s\n", wine_dbgstr_w(ValueName));
222 switch(ValueType)
224 case REG_NONE:
225 trace("ValueType: REG_NONE\n");
226 trace("ValueData: %p\n", ValueData);
227 break;
229 case REG_BINARY:
230 trace("ValueType: REG_BINARY\n");
231 trace("ValueData: %p\n", ValueData);
232 break;
234 case REG_SZ:
235 trace("ValueType: REG_SZ\n");
236 trace("ValueData: %s\n", (char*)ValueData);
237 break;
239 case REG_MULTI_SZ:
240 trace("ValueType: REG_MULTI_SZ\n");
241 trace("ValueData: %s\n", (char*)ValueData);
242 break;
244 case REG_EXPAND_SZ:
245 trace("ValueType: REG_EXPAND_SZ\n");
246 trace("ValueData: %s\n", (char*)ValueData);
247 break;
249 case REG_DWORD:
250 trace("ValueType: REG_DWORD\n");
251 trace("ValueData: %p\n", ValueData);
252 break;
254 trace("ValueLength: %d\n", (int)ValueLength);
256 if(CurrentTest == 0)
257 ok(1, "\n"); /*checks that QueryRoutine is called*/
258 if(CurrentTest > 7)
259 ok(!1, "Invalid Test Specified!\n");
261 CurrentTest++;
263 return ret;
266 static void test_RtlQueryRegistryValues(void)
270 ******************************
271 * QueryTable Flags *
272 ******************************
273 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
274 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
275 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
276 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
277 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
278 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
279 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
280 ******************************
283 **Test layout(numbered according to CurrentTest value)**
284 0)NOVALUE Just make sure call-back works
285 1)Null Name See if QueryRoutine is called for every value in current key
286 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
287 3)REQUIRED Test for value that's not there
288 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
289 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
290 6)DefaultType Test return values when key isn't present
291 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
292 8)DefaultLength Test Default Length with DefaultType = REG_SZ
293 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
294 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
295 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
296 12)Delete Try to delete value key
299 NTSTATUS status;
300 ULONG RelativeTo;
302 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
303 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
305 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
307 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
309 QueryTable[0].QueryRoutine = QueryRoutine;
310 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
311 QueryTable[0].Name = NULL;
312 QueryTable[0].EntryContext = NULL;
313 QueryTable[0].DefaultType = REG_BINARY;
314 QueryTable[0].DefaultData = NULL;
315 QueryTable[0].DefaultLength = 100;
317 QueryTable[1].QueryRoutine = QueryRoutine;
318 QueryTable[1].Flags = 0;
319 QueryTable[1].Name = NULL;
320 QueryTable[1].EntryContext = 0;
321 QueryTable[1].DefaultType = REG_NONE;
322 QueryTable[1].DefaultData = NULL;
323 QueryTable[1].DefaultLength = 0;
325 QueryTable[2].QueryRoutine = NULL;
326 QueryTable[2].Flags = 0;
327 QueryTable[2].Name = NULL;
328 QueryTable[2].EntryContext = 0;
329 QueryTable[2].DefaultType = REG_NONE;
330 QueryTable[2].DefaultData = NULL;
331 QueryTable[2].DefaultLength = 0;
333 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
334 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
336 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
339 static void test_NtOpenKey(void)
341 HANDLE key;
342 NTSTATUS status;
343 OBJECT_ATTRIBUTES attr;
344 ACCESS_MASK am = KEY_READ;
345 UNICODE_STRING str;
347 /* All NULL */
348 status = pNtOpenKey(NULL, 0, NULL);
349 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
351 /* NULL attributes */
352 status = pNtOpenKey(&key, 0, NULL);
353 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
354 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
356 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
358 /* NULL key */
359 status = pNtOpenKey(NULL, am, &attr);
360 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
362 /* Length > sizeof(OBJECT_ATTRIBUTES) */
363 attr.Length *= 2;
364 status = pNtOpenKey(&key, am, &attr);
365 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
367 /* Zero accessmask */
368 attr.Length = sizeof(attr);
369 key = (HANDLE)0xdeadbeef;
370 status = pNtOpenKey(&key, 0, &attr);
371 todo_wine
372 ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
373 todo_wine
374 ok(!key, "key = %p\n", key);
375 if (status == STATUS_SUCCESS) NtClose(key);
377 /* Calling without parent key requres full registry path. */
378 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
379 InitializeObjectAttributes(&attr, &str, 0, 0, 0);
380 key = (HANDLE)0xdeadbeef;
381 status = pNtOpenKey(&key, KEY_READ, &attr);
382 todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
383 todo_wine
384 ok(!key, "key = %p\n", key);
385 pRtlFreeUnicodeString( &str );
387 /* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
388 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine" );
389 status = pNtOpenKey(&key, KEY_READ, &attr);
390 todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey Failed: 0x%08x\n", status);
392 attr.Attributes = OBJ_CASE_INSENSITIVE;
393 status = pNtOpenKey(&key, KEY_READ, &attr);
394 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
395 pNtClose(key);
396 pRtlFreeUnicodeString( &str );
398 pRtlCreateUnicodeStringFromAsciiz( &str, "" );
399 status = pNtOpenKey(&key, KEY_READ, &attr);
400 todo_wine
401 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
402 pRtlFreeUnicodeString( &str );
404 pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
405 status = pNtOpenKey(&key, KEY_READ, &attr);
406 todo_wine
407 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
408 pRtlFreeUnicodeString( &str );
410 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
411 status = pNtOpenKey(&key, KEY_READ, &attr);
412 todo_wine
413 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
414 pNtClose( key );
415 pRtlFreeUnicodeString( &str );
417 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
418 status = pNtOpenKey(&key, KEY_READ, &attr);
419 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
420 pNtClose( key );
421 pRtlFreeUnicodeString( &str );
423 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
424 status = pNtOpenKey(&key, KEY_READ, &attr);
425 todo_wine
426 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
427 pRtlFreeUnicodeString( &str );
429 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
430 status = pNtOpenKey(&key, KEY_READ, &attr);
431 todo_wine
432 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
433 pRtlFreeUnicodeString( &str );
435 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
436 status = pNtOpenKey(&key, KEY_READ, &attr);
437 todo_wine
438 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status );
439 pRtlFreeUnicodeString( &str );
441 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
442 status = pNtOpenKey(&key, KEY_READ, &attr);
443 todo_wine
444 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status );
445 pRtlFreeUnicodeString( &str );
447 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
448 status = pNtOpenKey(&key, KEY_READ, &attr);
449 todo_wine
450 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status );
451 pRtlFreeUnicodeString( &str );
453 if (!pNtOpenKeyEx)
455 win_skip("NtOpenKeyEx not available\n");
456 return;
459 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
460 status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0);
461 ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status);
463 pNtClose(key);
466 static void test_NtCreateKey(void)
468 /*Create WineTest*/
469 OBJECT_ATTRIBUTES attr;
470 HANDLE key, subkey;
471 ACCESS_MASK am = GENERIC_ALL;
472 NTSTATUS status;
473 UNICODE_STRING str;
475 /* All NULL */
476 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
477 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
478 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
480 /* Only the key */
481 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
482 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
483 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
485 /* Only accessmask */
486 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
487 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
488 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
490 /* Key and accessmask */
491 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
492 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
493 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
495 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
497 /* Only attributes */
498 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
499 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
500 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
502 /* Length > sizeof(OBJECT_ATTRIBUTES) */
503 attr.Length *= 2;
504 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
505 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
507 attr.Length = sizeof(attr);
508 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
509 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
511 attr.RootDirectory = key;
512 attr.ObjectName = &str;
514 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
515 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
516 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
517 pRtlFreeUnicodeString( &str );
519 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
520 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
521 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
522 pRtlFreeUnicodeString( &str );
524 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
525 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
526 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
527 pRtlFreeUnicodeString( &str );
529 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
530 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
531 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
532 "NtCreateKey failed: 0x%08x\n", status );
533 if (status == STATUS_SUCCESS)
535 pNtDeleteKey( subkey );
536 pNtClose( subkey );
538 pRtlFreeUnicodeString( &str );
540 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
541 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
542 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
543 pRtlFreeUnicodeString( &str );
544 pNtDeleteKey( subkey );
545 pNtClose( subkey );
547 attr.RootDirectory = 0;
548 attr.Attributes = OBJ_CASE_INSENSITIVE;
550 pRtlCreateUnicodeStringFromAsciiz( &str, "" );
551 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
552 todo_wine
553 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
554 pRtlFreeUnicodeString( &str );
556 pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
557 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
558 todo_wine
559 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status );
560 pRtlFreeUnicodeString( &str );
562 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
563 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
564 todo_wine
565 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
566 "NtCreateKey failed: 0x%08x\n", status );
567 if (!status) pNtClose( subkey );
568 pRtlFreeUnicodeString( &str );
570 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
571 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
572 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
573 "NtCreateKey failed: 0x%08x\n", status );
574 if (!status) pNtClose( subkey );
575 pRtlFreeUnicodeString( &str );
577 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
578 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
579 todo_wine
580 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
581 pRtlFreeUnicodeString( &str );
583 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
584 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
585 todo_wine
586 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
587 pRtlFreeUnicodeString( &str );
589 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
590 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
591 todo_wine
592 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
593 pRtlFreeUnicodeString( &str );
595 pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
596 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
597 todo_wine
598 ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status );
599 pRtlFreeUnicodeString( &str );
601 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
602 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
603 todo_wine
604 ok( status == STATUS_OBJECT_TYPE_MISMATCH, "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 /* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */
615 attr.Attributes = 0;
616 pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
617 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
618 todo_wine
619 ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
620 pRtlFreeUnicodeString( &str );
622 pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\Machine\\Software\\Classes" );
623 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
624 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
625 "NtCreateKey failed: 0x%08x\n", status );
626 if (!status) pNtClose( subkey );
627 pRtlFreeUnicodeString( &str );
629 pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" );
630 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
631 ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
632 "NtCreateKey failed: 0x%08x\n", status );
633 if (!status) pNtClose( subkey );
634 pRtlFreeUnicodeString( &str );
636 pNtClose(key);
639 static void test_NtSetValueKey(void)
641 HANDLE key;
642 NTSTATUS status;
643 OBJECT_ATTRIBUTES attr;
644 ACCESS_MASK am = KEY_WRITE;
645 UNICODE_STRING ValName;
646 DWORD data = 711;
648 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
649 status = pNtOpenKey(&key, am, &attr);
650 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
652 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
653 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
654 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
655 pRtlFreeUnicodeString(&ValName);
657 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
658 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
659 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
660 pRtlFreeUnicodeString(&ValName);
662 pNtClose(key);
665 static void test_RtlOpenCurrentUser(void)
667 NTSTATUS status;
668 HANDLE handle;
669 status=pRtlOpenCurrentUser(KEY_READ, &handle);
670 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
671 pNtClose(handle);
674 static void test_RtlCheckRegistryKey(void)
676 static WCHAR empty[] = {0};
677 NTSTATUS status;
679 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
680 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
682 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
683 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
685 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, NULL);
686 ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and Path being NULL: 0x%08x\n", status);
688 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, empty);
689 ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and Path being empty: 0x%08x\n", status);
691 status = pRtlCheckRegistryKey(RTL_REGISTRY_USER, NULL);
692 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_USER and Path being NULL: 0x%08x\n", status);
694 status = pRtlCheckRegistryKey(RTL_REGISTRY_USER, empty);
695 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_USER and Path being empty: 0x%08x\n", status);
698 static void test_NtFlushKey(void)
700 NTSTATUS status;
701 HANDLE hkey;
702 OBJECT_ATTRIBUTES attr;
703 ACCESS_MASK am = KEY_ALL_ACCESS;
705 status = pNtFlushKey(NULL);
706 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
708 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
709 pNtOpenKey(&hkey, am, &attr);
711 status = pNtFlushKey(hkey);
712 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
714 pNtClose(hkey);
717 static void test_NtQueryValueKey(void)
719 HANDLE key;
720 NTSTATUS status;
721 OBJECT_ATTRIBUTES attr;
722 UNICODE_STRING ValName;
723 KEY_VALUE_BASIC_INFORMATION *basic_info;
724 KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi;
725 KEY_VALUE_FULL_INFORMATION *full_info;
726 DWORD len, expected;
728 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
730 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
731 status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr);
732 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
734 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
735 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
736 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
737 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
738 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
739 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
740 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
741 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
743 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
744 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
745 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
746 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
747 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
748 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
749 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
750 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
751 HeapFree(GetProcessHeap(), 0, basic_info);
753 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
754 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
755 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
756 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
757 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
758 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
759 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
760 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
762 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
763 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
764 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
765 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
766 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
767 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
768 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
769 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
770 HeapFree(GetProcessHeap(), 0, partial_info);
772 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
773 full_info = HeapAlloc(GetProcessHeap(), 0, len);
774 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
775 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
776 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
777 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
778 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
779 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
780 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
781 "NtQueryValueKey returned wrong len %d\n", len);
782 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
784 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
785 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
786 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
787 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
788 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
789 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
790 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
791 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
792 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
793 *(DWORD *)((char *)full_info + full_info->DataOffset));
794 HeapFree(GetProcessHeap(), 0, full_info);
796 pRtlFreeUnicodeString(&ValName);
797 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
799 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
800 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
801 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
802 memset(partial_info, 0xbd, len+1);
803 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
804 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
805 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
806 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
807 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
808 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
809 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
811 expected = len;
812 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
813 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
814 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
815 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
816 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
817 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
818 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
819 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
820 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
821 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
822 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
823 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
825 HeapFree(GetProcessHeap(), 0, partial_info);
826 pRtlFreeUnicodeString(&ValName);
828 pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest");
829 status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0);
830 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
832 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
833 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
834 ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type);
835 ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength);
836 pRtlFreeUnicodeString(&ValName);
838 pNtClose(key);
841 static void test_NtDeleteKey(void)
843 NTSTATUS status;
844 HANDLE hkey;
845 OBJECT_ATTRIBUTES attr;
846 ACCESS_MASK am = KEY_ALL_ACCESS;
848 status = pNtDeleteKey(NULL);
849 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
851 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
852 status = pNtOpenKey(&hkey, am, &attr);
853 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
855 status = pNtDeleteKey(hkey);
856 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
859 static void test_NtQueryLicenseKey(void)
861 static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
862 UNICODE_STRING name;
863 WORD buffer[32];
864 NTSTATUS status;
865 ULONG type, len;
866 DWORD value;
868 if (!pNtQueryLicenseValue)
870 win_skip("NtQueryLicenseValue not found, skipping tests\n");
871 return;
874 type = 0xdead;
875 len = 0xbeef;
876 memset(&name, 0, sizeof(name));
877 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
878 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
879 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
880 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
882 /* test with empty key */
883 pRtlCreateUnicodeStringFromAsciiz(&name, "");
885 type = 0xdead;
886 len = 0xbeef;
887 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
888 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
889 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
890 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
892 type = 0xdead;
893 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
894 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
895 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
897 len = 0xbeef;
898 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
899 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
900 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
902 type = 0xdead;
903 len = 0xbeef;
904 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
905 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
906 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
907 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
909 pRtlFreeUnicodeString(&name);
911 /* test with nonexistent licence key */
912 pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
914 type = 0xdead;
915 len = 0xbeef;
916 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
917 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
918 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
919 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
921 type = 0xdead;
922 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
923 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
924 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
926 len = 0xbeef;
927 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
928 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
929 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
931 type = 0xdead;
932 len = 0xbeef;
933 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
934 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n");
935 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
936 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
938 pRtlFreeUnicodeString(&name);
940 /* test with REG_SZ license key */
941 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
943 type = 0xdead;
944 len = 0xbeef;
945 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
946 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
947 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
948 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
950 type = 0xdead;
951 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
952 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
953 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
955 type = 0xdead;
956 len = 0;
957 status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
958 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
959 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
960 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
962 len = 0;
963 status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
964 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
965 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
967 type = 0xdead;
968 len = 0;
969 memset(buffer, 0x11, sizeof(buffer));
970 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
971 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
972 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
973 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
974 ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
976 type = 0xdead;
977 len = 0;
978 memset(buffer, 0x11, sizeof(buffer));
979 status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
980 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
981 ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
982 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
983 ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
985 pRtlFreeUnicodeString(&name);
987 /* test with REG_DWORD license key */
988 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
990 type = 0xdead;
991 len = 0xbeef;
992 status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
993 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
994 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
995 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
997 type = 0xdead;
998 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
999 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
1000 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
1002 type = 0xdead;
1003 len = 0;
1004 status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
1005 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
1006 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
1007 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1009 len = 0;
1010 status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
1011 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
1012 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1014 type = 0xdead;
1015 len = 0;
1016 value = 0xdeadbeef;
1017 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
1018 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
1019 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
1020 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1021 ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
1023 type = 0xdead;
1024 len = 0;
1025 status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
1026 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
1027 ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
1028 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
1030 pRtlFreeUnicodeString(&name);
1033 static void test_RtlpNtQueryValueKey(void)
1035 NTSTATUS status;
1037 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
1038 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
1041 static void test_symlinks(void)
1043 static const WCHAR linkW[] = {'l','i','n','k',0};
1044 static const WCHAR valueW[] = {'v','a','l','u','e',0};
1045 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
1046 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
1047 static UNICODE_STRING null_str;
1048 char buffer[1024];
1049 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1050 WCHAR *target;
1051 UNICODE_STRING symlink_str, link_str, target_str, value_str;
1052 HANDLE root, key, link;
1053 OBJECT_ATTRIBUTES attr;
1054 NTSTATUS status;
1055 DWORD target_len, len, dw;
1057 pRtlInitUnicodeString( &link_str, linkW );
1058 pRtlInitUnicodeString( &symlink_str, symlinkW );
1059 pRtlInitUnicodeString( &target_str, targetW + 1 );
1060 pRtlInitUnicodeString( &value_str, valueW );
1062 target_len = winetestpath.Length + sizeof(targetW);
1063 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
1064 memcpy( target, winetestpath.Buffer, winetestpath.Length );
1065 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
1067 attr.Length = sizeof(attr);
1068 attr.RootDirectory = 0;
1069 attr.Attributes = 0;
1070 attr.ObjectName = &winetestpath;
1071 attr.SecurityDescriptor = NULL;
1072 attr.SecurityQualityOfService = NULL;
1074 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1075 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1077 attr.RootDirectory = root;
1078 attr.ObjectName = &link_str;
1079 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1080 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1082 /* REG_SZ is not allowed */
1083 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
1084 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1085 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1086 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1087 /* other values are not allowed */
1088 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1089 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
1091 /* try opening the target through the link */
1093 attr.ObjectName = &link_str;
1094 key = (HANDLE)0xdeadbeef;
1095 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1096 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1097 ok( !key, "key = %p\n", key );
1099 attr.ObjectName = &target_str;
1100 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1101 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1103 dw = 0xbeef;
1104 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1105 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1106 pNtClose( key );
1108 attr.ObjectName = &link_str;
1109 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1110 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1112 len = sizeof(buffer);
1113 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1114 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1115 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1117 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1118 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1120 /* REG_LINK can be created in non-link keys */
1121 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
1122 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1123 len = sizeof(buffer);
1124 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1125 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1126 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1127 "wrong len %u\n", len );
1128 status = pNtDeleteValueKey( key, &symlink_str );
1129 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
1131 pNtClose( key );
1133 attr.Attributes = 0;
1134 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1135 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1137 len = sizeof(buffer);
1138 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1139 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1140 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
1142 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1143 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1144 pNtClose( key );
1146 /* now open the symlink itself */
1148 attr.RootDirectory = root;
1149 attr.Attributes = OBJ_OPENLINK;
1150 attr.ObjectName = &link_str;
1151 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1152 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1154 len = sizeof(buffer);
1155 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1156 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1157 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1158 "wrong len %u\n", len );
1159 pNtClose( key );
1161 if (pNtOpenKeyEx)
1163 /* REG_OPTION_OPEN_LINK flag doesn't matter */
1164 status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
1165 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1167 len = sizeof(buffer);
1168 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1169 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1170 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1171 "wrong len %u\n", len );
1172 pNtClose( key );
1174 status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 );
1175 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1177 len = sizeof(buffer);
1178 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1179 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1180 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1181 "wrong len %u\n", len );
1182 pNtClose( key );
1184 attr.Attributes = 0;
1185 status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
1186 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1188 len = sizeof(buffer);
1189 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1190 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1191 pNtClose( key );
1194 attr.Attributes = OBJ_OPENLINK;
1195 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1196 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1197 len = sizeof(buffer);
1198 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1199 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1200 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1201 "wrong len %u\n", len );
1202 pNtClose( key );
1204 /* delete target and create by NtCreateKey on link */
1205 attr.ObjectName = &target_str;
1206 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1207 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1208 status = pNtDeleteKey( key );
1209 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1210 pNtClose( key );
1212 attr.ObjectName = &link_str;
1213 attr.Attributes = 0;
1214 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1215 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1217 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1218 todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1219 pNtClose( key );
1220 if (status) /* can be removed once todo_wine above is fixed */
1222 attr.ObjectName = &target_str;
1223 attr.Attributes = OBJ_OPENLINK;
1224 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1225 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1226 pNtClose( key );
1229 attr.ObjectName = &target_str;
1230 attr.Attributes = OBJ_OPENLINK;
1231 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1232 ok( status == STATUS_SUCCESS, "NtOpenKey wrong status 0x%08x\n", status );
1234 if (0) /* crashes the Windows kernel on some Vista systems */
1236 /* reopen the link from itself */
1238 attr.RootDirectory = link;
1239 attr.Attributes = OBJ_OPENLINK;
1240 attr.ObjectName = &null_str;
1241 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1242 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1243 len = sizeof(buffer);
1244 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1245 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1246 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1247 "wrong len %u\n", len );
1248 pNtClose( key );
1250 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1251 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1252 len = sizeof(buffer);
1253 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1254 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1255 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
1256 "wrong len %u\n", len );
1257 pNtClose( key );
1260 if (0) /* crashes the Windows kernel in most versions */
1262 attr.RootDirectory = link;
1263 attr.Attributes = 0;
1264 attr.ObjectName = &null_str;
1265 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1266 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1267 len = sizeof(buffer);
1268 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1269 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1270 pNtClose( key );
1272 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1273 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1274 len = sizeof(buffer);
1275 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1276 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1277 pNtClose( key );
1280 /* target with terminating null doesn't work */
1281 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
1282 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1283 attr.RootDirectory = root;
1284 attr.Attributes = 0;
1285 attr.ObjectName = &link_str;
1286 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1287 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1289 /* relative symlink, works only on win2k */
1290 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
1291 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1292 attr.ObjectName = &link_str;
1293 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1294 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
1295 "NtOpenKey wrong status 0x%08x\n", status );
1297 key = (HKEY)0xdeadbeef;
1298 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, NULL );
1299 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
1300 ok( !key, "key = %p\n", key );
1302 status = pNtDeleteKey( link );
1303 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1304 pNtClose( link );
1306 attr.ObjectName = &target_str;
1307 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1308 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1309 status = pNtDeleteKey( key );
1310 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1311 pNtClose( key );
1313 /* symlink loop */
1315 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1316 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1317 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
1318 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
1319 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
1320 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1322 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1323 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
1324 "NtOpenKey failed: 0x%08x\n", status );
1326 attr.Attributes = OBJ_OPENLINK;
1327 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1328 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1329 pNtClose( key );
1331 status = pNtDeleteKey( link );
1332 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1333 pNtClose( link );
1335 status = pNtDeleteKey( root );
1336 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1337 pNtClose( root );
1339 pRtlFreeHeap(GetProcessHeap(), 0, target);
1342 static WCHAR valueW[] = {'v','a','l','u','e'};
1343 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
1344 static const DWORD ptr_size = 8 * sizeof(void*);
1346 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
1348 char tmp[32];
1349 NTSTATUS status;
1350 OBJECT_ATTRIBUTES attr;
1351 UNICODE_STRING str;
1352 HANDLE key;
1353 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
1354 DWORD dw, len = sizeof(tmp);
1356 attr.Length = sizeof(attr);
1357 attr.RootDirectory = root;
1358 attr.Attributes = OBJ_CASE_INSENSITIVE;
1359 attr.ObjectName = &str;
1360 attr.SecurityDescriptor = NULL;
1361 attr.SecurityQualityOfService = NULL;
1362 pRtlCreateUnicodeStringFromAsciiz( &str, name );
1364 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1365 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
1366 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
1368 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1369 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1370 dw = 0;
1371 else
1373 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
1374 dw = *(DWORD *)info->Data;
1376 pNtClose( key );
1377 pRtlFreeUnicodeString( &str );
1378 return dw;
1381 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
1383 DWORD dw = get_key_value( root, name, flags );
1384 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
1386 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
1388 static void test_redirection(void)
1390 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1391 'M','a','c','h','i','n','e','\\',
1392 'S','o','f','t','w','a','r','e',0};
1393 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1394 'M','a','c','h','i','n','e','\\',
1395 'S','o','f','t','w','a','r','e','\\',
1396 'W','o','w','6','4','3','2','N','o','d','e',0};
1397 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1398 'M','a','c','h','i','n','e','\\',
1399 'S','o','f','t','w','a','r','e','\\',
1400 'W','i','n','e',0};
1401 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1402 'M','a','c','h','i','n','e','\\',
1403 'S','o','f','t','w','a','r','e','\\',
1404 'W','o','w','6','4','3','2','N','o','d','e','\\',
1405 'W','i','n','e',0};
1406 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1407 'M','a','c','h','i','n','e','\\',
1408 'S','o','f','t','w','a','r','e','\\',
1409 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
1410 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1411 'M','a','c','h','i','n','e','\\',
1412 'S','o','f','t','w','a','r','e','\\',
1413 'W','o','w','6','4','3','2','N','o','d','e','\\',
1414 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
1415 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1416 'M','a','c','h','i','n','e','\\',
1417 'S','o','f','t','w','a','r','e','\\',
1418 'C','l','a','s','s','e','s','\\',
1419 'W','i','n','e',0};
1420 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1421 'M','a','c','h','i','n','e','\\',
1422 'S','o','f','t','w','a','r','e','\\',
1423 'C','l','a','s','s','e','s','\\',
1424 'W','o','w','6','4','3','2','N','o','d','e','\\',
1425 'W','i','n','e',0};
1426 NTSTATUS status;
1427 OBJECT_ATTRIBUTES attr;
1428 UNICODE_STRING str;
1429 char buffer[1024];
1430 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1431 DWORD dw, len;
1432 HANDLE key, root32, root64, key32, key64;
1433 BOOL is_vista = FALSE;
1435 if (ptr_size != 64)
1437 ULONG is_wow64, len;
1438 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
1439 &is_wow64, sizeof(is_wow64), &len ) ||
1440 !is_wow64)
1442 trace( "Not on Wow64, no redirection\n" );
1443 return;
1447 attr.Length = sizeof(attr);
1448 attr.RootDirectory = 0;
1449 attr.Attributes = OBJ_CASE_INSENSITIVE;
1450 attr.ObjectName = &str;
1451 attr.SecurityDescriptor = NULL;
1452 attr.SecurityQualityOfService = NULL;
1454 pRtlInitUnicodeString( &str, wine64W );
1455 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1456 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1458 pRtlInitUnicodeString( &str, wine32W );
1459 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1460 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1462 pRtlInitUnicodeString( &str, key64W );
1463 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1464 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1466 pRtlInitUnicodeString( &str, key32W );
1467 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1468 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1470 dw = 64;
1471 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1472 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1474 dw = 32;
1475 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1476 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1478 len = sizeof(buffer);
1479 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1480 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1481 dw = *(DWORD *)info->Data;
1482 ok( dw == 32, "wrong value %u\n", dw );
1484 len = sizeof(buffer);
1485 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1486 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1487 dw = *(DWORD *)info->Data;
1488 ok( dw == 64, "wrong value %u\n", dw );
1490 pRtlInitUnicodeString( &str, softwareW );
1491 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1492 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1494 if (ptr_size == 32)
1496 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1497 /* the new (and simpler) Win7 mechanism doesn't */
1498 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1500 trace( "using Vista-style Wow6432Node handling\n" );
1501 is_vista = TRUE;
1503 check_key_value( key, "Wine\\Winetest", 0, 32 );
1504 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1505 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1506 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1507 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1508 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1510 else
1512 check_key_value( key, "Wine\\Winetest", 0, 64 );
1513 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1515 pNtClose( key );
1517 if (ptr_size == 32)
1519 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1520 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1521 dw = get_key_value( key, "Wine\\Winetest", 0 );
1522 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1523 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1524 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1525 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1526 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1527 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1528 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1529 pNtClose( key );
1531 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1532 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1533 check_key_value( key, "Wine\\Winetest", 0, 32 );
1534 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1535 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1536 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1537 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1538 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1539 pNtClose( key );
1542 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1543 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1544 if (ptr_size == 64)
1546 /* KEY_WOW64 flags have no effect on 64-bit */
1547 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1548 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1549 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1550 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1552 else
1554 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1555 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1556 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1557 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1560 pRtlInitUnicodeString( &str, wownodeW );
1561 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1562 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1563 check_key_value( key, "Wine\\Winetest", 0, 32 );
1564 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1565 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1566 pNtClose( key );
1568 if (ptr_size == 32)
1570 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1571 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1572 dw = get_key_value( key, "Wine\\Winetest", 0 );
1573 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1574 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1575 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1576 pNtClose( key );
1578 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1579 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1580 check_key_value( key, "Wine\\Winetest", 0, 32 );
1581 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1582 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1583 pNtClose( key );
1586 pRtlInitUnicodeString( &str, wine32W );
1587 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1588 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1589 check_key_value( key, "Winetest", 0, 32 );
1590 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1591 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1592 pNtClose( key );
1594 if (ptr_size == 32)
1596 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1597 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1598 dw = get_key_value( key, "Winetest", 0 );
1599 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1600 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1601 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1602 pNtClose( key );
1604 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1605 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1606 check_key_value( key, "Winetest", 0, 32 );
1607 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1608 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1609 pNtClose( key );
1612 pRtlInitUnicodeString( &str, wine64W );
1613 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1614 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1615 check_key_value( key, "Winetest", 0, ptr_size );
1616 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1617 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1618 pNtClose( key );
1620 if (ptr_size == 32)
1622 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1623 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1624 dw = get_key_value( key, "Winetest", 0 );
1625 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1626 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1627 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1628 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1629 pNtClose( key );
1631 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1632 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1633 check_key_value( key, "Winetest", 0, 32 );
1634 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1635 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1636 pNtClose( key );
1639 status = pNtDeleteKey( key32 );
1640 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1641 pNtClose( key32 );
1643 status = pNtDeleteKey( key64 );
1644 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1645 pNtClose( key64 );
1647 pNtDeleteKey( root32 );
1648 pNtClose( root32 );
1649 pNtDeleteKey( root64 );
1650 pNtClose( root64 );
1652 /* Software\Classes is shared/reflected so behavior is different */
1654 pRtlInitUnicodeString( &str, classes64W );
1655 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1656 if (status == STATUS_ACCESS_DENIED)
1658 skip("Not authorized to modify the Classes key\n");
1659 return;
1661 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1663 pRtlInitUnicodeString( &str, classes32W );
1664 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1665 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1667 dw = 64;
1668 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1669 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1670 pNtClose( key64 );
1672 dw = 32;
1673 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1674 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1675 pNtClose( key32 );
1677 pRtlInitUnicodeString( &str, classes64W );
1678 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1679 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1680 len = sizeof(buffer);
1681 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1682 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1683 dw = *(DWORD *)info->Data;
1684 ok( dw == ptr_size, "wrong value %u\n", dw );
1686 pRtlInitUnicodeString( &str, classes32W );
1687 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1688 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1689 len = sizeof(buffer);
1690 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1691 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1692 dw = *(DWORD *)info->Data;
1693 ok( dw == 32, "wrong value %u\n", dw );
1695 pNtDeleteKey( key32 );
1696 pNtClose( key32 );
1697 pNtDeleteKey( key64 );
1698 pNtClose( key64 );
1701 static void test_long_value_name(void)
1703 HANDLE key;
1704 NTSTATUS status, expected;
1705 OBJECT_ATTRIBUTES attr;
1706 UNICODE_STRING ValName;
1707 DWORD i;
1709 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1710 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1711 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1713 ValName.MaximumLength = 0xfffc;
1714 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1715 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1716 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1717 ValName.Buffer[i] = 'a';
1718 ValName.Buffer[i] = 0;
1720 status = pNtDeleteValueKey(key, &ValName);
1721 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1722 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1723 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1724 "NtSetValueKey with long value name returned 0x%08x\n", status);
1725 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1726 status = pNtDeleteValueKey(key, &ValName);
1727 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1729 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1730 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1732 pRtlFreeUnicodeString(&ValName);
1733 pNtClose(key);
1736 static void test_NtQueryKey(void)
1738 HANDLE key, subkey, subkey2;
1739 NTSTATUS status;
1740 OBJECT_ATTRIBUTES attr;
1741 ULONG length, len;
1742 KEY_NAME_INFORMATION *info = NULL;
1743 KEY_CACHED_INFORMATION cached_info;
1744 UNICODE_STRING str;
1745 DWORD dw;
1747 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1748 status = pNtOpenKey(&key, KEY_READ, &attr);
1749 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1751 status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
1752 if (status == STATUS_INVALID_PARAMETER) {
1753 win_skip("KeyNameInformation is not supported\n");
1754 pNtClose(key);
1755 return;
1757 todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1758 info = HeapAlloc(GetProcessHeap(), 0, length);
1760 /* non-zero buffer size, but insufficient */
1761 status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
1762 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
1763 ok(length == len, "got %d, expected %d\n", len, length);
1764 ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
1765 info->NameLength, winetestpath.Length);
1767 /* correct buffer size */
1768 status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
1769 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1770 ok(length == len, "got %d, expected %d\n", len, length);
1772 str.Buffer = info->Name;
1773 str.Length = info->NameLength;
1774 ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1775 "got %s, expected %s\n",
1776 wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1777 wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1779 HeapFree(GetProcessHeap(), 0, info);
1781 attr.RootDirectory = key;
1782 attr.ObjectName = &str;
1783 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1784 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1785 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1786 pRtlFreeUnicodeString(&str);
1788 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1789 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1791 if (status == STATUS_SUCCESS)
1793 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1794 ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1795 ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1796 ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
1797 ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1798 ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1799 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1802 attr.RootDirectory = subkey;
1803 attr.ObjectName = &str;
1804 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
1805 status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
1806 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1807 pRtlFreeUnicodeString(&str);
1809 pRtlCreateUnicodeStringFromAsciiz(&str, "val");
1810 dw = 64;
1811 status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
1812 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1813 pRtlFreeUnicodeString(&str);
1815 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1816 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1818 if (status == STATUS_SUCCESS)
1820 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1821 ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1822 ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1823 ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
1824 ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1825 ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1826 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1829 status = pNtDeleteKey(subkey2);
1830 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1831 status = pNtDeleteKey(subkey);
1832 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1834 pNtClose(subkey2);
1835 pNtClose(subkey);
1836 pNtClose(key);
1839 static void test_notify(void)
1841 OBJECT_ATTRIBUTES attr;
1842 LARGE_INTEGER timeout;
1843 IO_STATUS_BLOCK iosb;
1844 UNICODE_STRING str;
1845 HANDLE key, events[2], subkey;
1846 NTSTATUS status;
1848 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1849 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1850 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1852 events[0] = CreateEventW(NULL, FALSE, TRUE, NULL);
1853 ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError());
1854 events[1] = CreateEventW(NULL, FALSE, TRUE, NULL);
1855 ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError());
1857 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1858 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1859 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1860 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1862 timeout.QuadPart = 0;
1863 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1864 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1865 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1866 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1868 attr.RootDirectory = key;
1869 attr.ObjectName = &str;
1871 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1872 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1873 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1874 pRtlFreeUnicodeString(&str);
1876 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1877 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1878 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1879 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
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 status = pNtDeleteKey(subkey);
1887 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1889 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1890 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1891 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1892 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1894 pNtClose(subkey);
1896 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1897 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1898 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1899 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1901 pNtClose(key);
1903 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1904 todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1905 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1906 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1908 if (pNtNotifyChangeMultipleKeys)
1910 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1911 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1912 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1914 status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1915 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1917 timeout.QuadPart = 0;
1918 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1919 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1921 attr.RootDirectory = key;
1922 attr.ObjectName = &str;
1923 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1924 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1925 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1926 pRtlFreeUnicodeString(&str);
1928 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1929 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1931 status = pNtDeleteKey(subkey);
1932 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1933 pNtClose(subkey);
1934 pNtClose(key);
1936 else
1938 win_skip("NtNotifyChangeMultipleKeys not available\n");
1941 pNtClose(events[0]);
1942 pNtClose(events[1]);
1945 static void test_RtlCreateRegistryKey(void)
1947 static WCHAR empty[] = {0};
1948 static const WCHAR key1[] = {'\\','R','t','l','C','r','e','a','t','e','R','e','g','i','s','t','r','y','K','e','y',0};
1949 UNICODE_STRING str;
1950 SIZE_T size;
1951 NTSTATUS status;
1953 RtlDuplicateUnicodeString(1, &winetestpath, &str);
1954 size = str.MaximumLength + sizeof(key1)* sizeof(WCHAR) * 2;
1955 str.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, str.Buffer, size);
1956 str.MaximumLength = size;
1957 pRtlAppendUnicodeToString(&str, key1);
1958 pRtlAppendUnicodeToString(&str, key1);
1960 /* should work */
1961 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
1962 ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08x\n", status);
1964 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, winetestpath.Buffer);
1965 ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08x\n", status);
1967 status = pRtlCreateRegistryKey(RTL_REGISTRY_USER, NULL);
1968 ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08x\n", status);
1970 status = pRtlCreateRegistryKey(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL, NULL);
1971 ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08x\n", status);
1973 status = pRtlCreateRegistryKey(RTL_REGISTRY_USER, empty);
1974 ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08x\n", status);
1976 status = pRtlCreateRegistryKey(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL, empty);
1977 ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08x\n", status);
1979 /* invalid first parameter */
1980 status = pRtlCreateRegistryKey(RTL_REGISTRY_USER+1, winetestpath.Buffer);
1981 ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_INVALID_PARAMETER);
1983 status = pRtlCreateRegistryKey((RTL_REGISTRY_USER+1) | RTL_REGISTRY_OPTIONAL, winetestpath.Buffer);
1984 ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_INVALID_PARAMETER);
1986 /* invalid second parameter */
1987 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, NULL);
1988 ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
1990 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, NULL);
1991 ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
1993 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, empty);
1994 ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
1996 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, empty);
1997 ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
1999 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, str.Buffer);
2000 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_OBJECT_NAME_NOT_FOUND);
2002 status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, str.Buffer);
2003 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_OBJECT_NAME_NOT_FOUND);
2005 /* both parameters invalid */
2006 status = pRtlCreateRegistryKey(RTL_REGISTRY_USER+1, NULL);
2007 ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_INVALID_PARAMETER);
2009 status = pRtlCreateRegistryKey((RTL_REGISTRY_USER+1) | RTL_REGISTRY_OPTIONAL, NULL);
2010 ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08x, expected %08x\n", status, STATUS_INVALID_PARAMETER);
2013 START_TEST(reg)
2015 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
2016 if(!InitFunctionPtrs())
2017 return;
2018 pRtlFormatCurrentUserKeyPath(&winetestpath);
2019 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
2020 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
2021 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
2023 pRtlAppendUnicodeToString(&winetestpath, winetest);
2025 test_NtCreateKey();
2026 test_NtOpenKey();
2027 test_NtSetValueKey();
2028 test_RtlCheckRegistryKey();
2029 test_RtlOpenCurrentUser();
2030 test_RtlQueryRegistryValues();
2031 test_RtlpNtQueryValueKey();
2032 test_NtFlushKey();
2033 test_NtQueryKey();
2034 test_NtQueryLicenseKey();
2035 test_NtQueryValueKey();
2036 test_long_value_name();
2037 test_notify();
2038 test_RtlCreateRegistryKey();
2039 test_NtDeleteKey();
2040 test_symlinks();
2041 test_redirection();
2043 pRtlFreeUnicodeString(&winetestpath);
2045 FreeLibrary(hntdll);