[NTDLL_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / rostests / winetests / ntdll / reg.c
1 /* Unit test suite for Rtl* Registry API functions
2 *
3 * Copyright 2003 Thomas Mertes
4 * Copyright 2005 Brad DeMorrow
5 *
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.
10 *
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.
15 *
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
19 *
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
22 *
23 */
24
25 #include "ntdll_test.h"
26 #include "wine/winternl.h"
27 #include "stdio.h"
28 #include "winnt.h"
29 #include "winnls.h"
30 #include "stdlib.h"
31
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))
36
37 #ifndef __WINE_WINTERNL_H
38
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
46
47 #define RTL_REGISTRY_HANDLE 0x40000000
48 #define RTL_REGISTRY_OPTIONAL 0x80000000
49
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
57
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);
64
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;
74
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;
81
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;
88
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;
97
98 typedef enum _KEY_VALUE_INFORMATION_CLASS {
99 KeyValueBasicInformation,
100 KeyValueFullInformation,
101 KeyValuePartialInformation,
102 KeyValueFullInformationAlign64,
103 KeyValuePartialInformationAlign64
104 } KEY_VALUE_INFORMATION_CLASS;
105
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)
115
116 #endif
117
118 static BOOLEAN (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR);
119 static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR);
120 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
121 static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING);
122 static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID);
123 static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR);
124 static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE);
125 static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
126 static NTSTATUS (WINAPI * pNtOpenKeyEx)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG);
127 static NTSTATUS (WINAPI * pNtClose)(IN HANDLE);
128 static NTSTATUS (WINAPI * pNtFlushKey)(HANDLE);
129 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
130 static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
131 ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
132 PULONG dispos );
133 static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,KEY_INFORMATION_CLASS,PVOID,ULONG,PULONG);
134 static NTSTATUS (WINAPI * pNtQueryLicenseValue)(const UNICODE_STRING *,ULONG *,PVOID,ULONG,ULONG *);
135 static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
136 static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
137 ULONG, const void*, ULONG );
138 static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
139 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
140 static LONG (WINAPI * pRtlCompareUnicodeString)(const PUNICODE_STRING,const PUNICODE_STRING,BOOLEAN);
141 static BOOLEAN (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR);
142 static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
143 static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
144 static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL);
145 static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID);
146 static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG);
147 static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG);
148 static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *);
149 static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN);
150 static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE,
151 void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN);
152 static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*);
153
154 static HMODULE hntdll = 0;
155 static int CurrentTest = 0;
156 static UNICODE_STRING winetestpath;
157
158 #define NTDLL_GET_PROC(func) \
159 p ## func = (void*)GetProcAddress(hntdll, #func); \
160 if(!p ## func) { \
161 trace("GetProcAddress(%s) failed\n", #func); \
162 FreeLibrary(hntdll); \
163 return FALSE; \
164 }
165
166 static BOOL InitFunctionPtrs(void)
167 {
168 hntdll = LoadLibraryA("ntdll.dll");
169 if(!hntdll) {
170 trace("Could not load ntdll.dll\n");
171 return FALSE;
172 }
173 NTDLL_GET_PROC(RtlInitUnicodeString)
174 NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
175 NTDLL_GET_PROC(RtlCreateUnicodeString)
176 NTDLL_GET_PROC(RtlFreeUnicodeString)
177 NTDLL_GET_PROC(RtlQueryRegistryValues)
178 NTDLL_GET_PROC(RtlCheckRegistryKey)
179 NTDLL_GET_PROC(RtlOpenCurrentUser)
180 NTDLL_GET_PROC(NtClose)
181 NTDLL_GET_PROC(NtDeleteValueKey)
182 NTDLL_GET_PROC(NtCreateKey)
183 NTDLL_GET_PROC(NtFlushKey)
184 NTDLL_GET_PROC(NtDeleteKey)
185 NTDLL_GET_PROC(NtQueryKey)
186 NTDLL_GET_PROC(NtQueryValueKey)
187 NTDLL_GET_PROC(NtQueryInformationProcess)
188 NTDLL_GET_PROC(NtSetValueKey)
189 NTDLL_GET_PROC(NtOpenKey)
190 NTDLL_GET_PROC(NtNotifyChangeKey)
191 NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
192 NTDLL_GET_PROC(RtlCompareUnicodeString)
193 NTDLL_GET_PROC(RtlReAllocateHeap)
194 NTDLL_GET_PROC(RtlAppendUnicodeToString)
195 NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
196 NTDLL_GET_PROC(RtlFreeHeap)
197 NTDLL_GET_PROC(RtlAllocateHeap)
198 NTDLL_GET_PROC(RtlZeroMemory)
199 NTDLL_GET_PROC(RtlpNtQueryValueKey)
200 NTDLL_GET_PROC(RtlOpenCurrentUser)
201 NTDLL_GET_PROC(NtWaitForSingleObject)
202
203 /* optional functions */
204 pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue");
205 pNtOpenKeyEx = (void *)GetProcAddress(hntdll, "NtOpenKeyEx");
206 pNtNotifyChangeMultipleKeys = (void *)GetProcAddress(hntdll, "NtNotifyChangeMultipleKeys");
207
208 return TRUE;
209 }
210 #undef NTDLL_GET_PROC
211
212 static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData,
213 IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
214 {
215 NTSTATUS ret = STATUS_SUCCESS;
216
217 trace("**Test %d**\n", CurrentTest);
218 trace("ValueName: %s\n", wine_dbgstr_w(ValueName));
219
220 switch(ValueType)
221 {
222 case REG_NONE:
223 trace("ValueType: REG_NONE\n");
224 trace("ValueData: %p\n", ValueData);
225 break;
226
227 case REG_BINARY:
228 trace("ValueType: REG_BINARY\n");
229 trace("ValueData: %p\n", ValueData);
230 break;
231
232 case REG_SZ:
233 trace("ValueType: REG_SZ\n");
234 trace("ValueData: %s\n", (char*)ValueData);
235 break;
236
237 case REG_MULTI_SZ:
238 trace("ValueType: REG_MULTI_SZ\n");
239 trace("ValueData: %s\n", (char*)ValueData);
240 break;
241
242 case REG_EXPAND_SZ:
243 trace("ValueType: REG_EXPAND_SZ\n");
244 trace("ValueData: %s\n", (char*)ValueData);
245 break;
246
247 case REG_DWORD:
248 trace("ValueType: REG_DWORD\n");
249 trace("ValueData: %p\n", ValueData);
250 break;
251 };
252 trace("ValueLength: %d\n", (int)ValueLength);
253
254 if(CurrentTest == 0)
255 ok(1, "\n"); /*checks that QueryRoutine is called*/
256 if(CurrentTest > 7)
257 ok(!1, "Invalid Test Specified!\n");
258
259 CurrentTest++;
260
261 return ret;
262 }
263
264 static void test_RtlQueryRegistryValues(void)
265 {
266
267 /*
268 ******************************
269 * QueryTable Flags *
270 ******************************
271 *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path
272 *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path
273 *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present
274 *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back
275 *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables!
276 *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored)
277 *RTL_QUERY_REGISTRY_DELETE * Delete value key after query
278 ******************************
279
280
281 **Test layout(numbered according to CurrentTest value)**
282 0)NOVALUE Just make sure call-back works
283 1)Null Name See if QueryRoutine is called for every value in current key
284 2)SUBKEY See if we can use SUBKEY to change the current path on the fly
285 3)REQUIRED Test for value that's not there
286 4)NOEXPAND See if it will return multiple strings(no expand should split strings up)
287 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine
288 6)DefaultType Test return values when key isn't present
289 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set)
290 8)DefaultLength Test Default Length with DefaultType = REG_SZ
291 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ
292 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ
293 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be)
294 12)Delete Try to delete value key
295
296 */
297 NTSTATUS status;
298 ULONG RelativeTo;
299
300 PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
301 RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/
302
303 QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26);
304
305 pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26);
306
307 QueryTable[0].QueryRoutine = QueryRoutine;
308 QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE;
309 QueryTable[0].Name = NULL;
310 QueryTable[0].EntryContext = NULL;
311 QueryTable[0].DefaultType = REG_BINARY;
312 QueryTable[0].DefaultData = NULL;
313 QueryTable[0].DefaultLength = 100;
314
315 QueryTable[1].QueryRoutine = QueryRoutine;
316 QueryTable[1].Flags = 0;
317 QueryTable[1].Name = NULL;
318 QueryTable[1].EntryContext = 0;
319 QueryTable[1].DefaultType = REG_NONE;
320 QueryTable[1].DefaultData = NULL;
321 QueryTable[1].DefaultLength = 0;
322
323 QueryTable[2].QueryRoutine = NULL;
324 QueryTable[2].Flags = 0;
325 QueryTable[2].Name = NULL;
326 QueryTable[2].EntryContext = 0;
327 QueryTable[2].DefaultType = REG_NONE;
328 QueryTable[2].DefaultData = NULL;
329 QueryTable[2].DefaultLength = 0;
330
331 status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0);
332 ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status);
333
334 pRtlFreeHeap(GetProcessHeap(), 0, QueryTable);
335 }
336
337 static void test_NtOpenKey(void)
338 {
339 HANDLE key;
340 NTSTATUS status;
341 OBJECT_ATTRIBUTES attr;
342 ACCESS_MASK am = KEY_READ;
343
344 /* All NULL */
345 status = pNtOpenKey(NULL, 0, NULL);
346 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
347
348 /* NULL attributes */
349 status = pNtOpenKey(&key, 0, NULL);
350 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
351 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
352
353 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
354
355 /* NULL key */
356 status = pNtOpenKey(NULL, am, &attr);
357 ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status);
358
359 /* Length > sizeof(OBJECT_ATTRIBUTES) */
360 attr.Length *= 2;
361 status = pNtOpenKey(&key, am, &attr);
362 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
363
364 if (!pNtOpenKeyEx)
365 {
366 win_skip("NtOpenKeyEx not available\n");
367 return;
368 }
369
370 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
371 status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0);
372 ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status);
373
374 pNtClose(key);
375 }
376
377 static void test_NtCreateKey(void)
378 {
379 /*Create WineTest*/
380 OBJECT_ATTRIBUTES attr;
381 HANDLE key, subkey;
382 ACCESS_MASK am = GENERIC_ALL;
383 NTSTATUS status;
384 UNICODE_STRING str;
385
386 /* All NULL */
387 status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0);
388 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
389 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
390
391 /* Only the key */
392 status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0);
393 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
394 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
395
396 /* Only accessmask */
397 status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0);
398 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
399 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
400
401 /* Key and accessmask */
402 status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0);
403 ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */,
404 "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status);
405
406 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
407
408 /* Only attributes */
409 status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0);
410 ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */,
411 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
412
413 /* Length > sizeof(OBJECT_ATTRIBUTES) */
414 attr.Length *= 2;
415 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
416 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
417
418 attr.Length = sizeof(attr);
419 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
420 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
421
422 attr.RootDirectory = key;
423 attr.ObjectName = &str;
424
425 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
426 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
427 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
428 pRtlFreeUnicodeString( &str );
429
430 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" );
431 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
432 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
433 pRtlFreeUnicodeString( &str );
434
435 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
436 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
437 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
438 pRtlFreeUnicodeString( &str );
439
440 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
441 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
442 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
443 "NtCreateKey failed: 0x%08x\n", status );
444 if (status == STATUS_SUCCESS)
445 {
446 pNtDeleteKey( subkey );
447 pNtClose( subkey );
448 }
449 pRtlFreeUnicodeString( &str );
450
451 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
452 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
453 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
454 pRtlFreeUnicodeString( &str );
455 pNtDeleteKey( subkey );
456 pNtClose( subkey );
457
458 pNtClose(key);
459 }
460
461 static void test_NtSetValueKey(void)
462 {
463 HANDLE key;
464 NTSTATUS status;
465 OBJECT_ATTRIBUTES attr;
466 ACCESS_MASK am = KEY_WRITE;
467 UNICODE_STRING ValName;
468 DWORD data = 711;
469
470 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
471 status = pNtOpenKey(&key, am, &attr);
472 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
473
474 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
475 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
476 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
477 pRtlFreeUnicodeString(&ValName);
478
479 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
480 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
481 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
482 pRtlFreeUnicodeString(&ValName);
483
484 pNtClose(key);
485 }
486
487 static void test_RtlOpenCurrentUser(void)
488 {
489 NTSTATUS status;
490 HANDLE handle;
491 status=pRtlOpenCurrentUser(KEY_READ, &handle);
492 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
493 pNtClose(handle);
494 }
495
496 static void test_RtlCheckRegistryKey(void)
497 {
498 NTSTATUS status;
499
500 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
501 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
502
503 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
504 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
505 }
506
507 static void test_NtFlushKey(void)
508 {
509 NTSTATUS status;
510 HANDLE hkey;
511 OBJECT_ATTRIBUTES attr;
512 ACCESS_MASK am = KEY_ALL_ACCESS;
513
514 status = pNtFlushKey(NULL);
515 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
516
517 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
518 pNtOpenKey(&hkey, am, &attr);
519
520 status = pNtFlushKey(hkey);
521 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
522
523 pNtClose(hkey);
524 }
525
526 static void test_NtQueryValueKey(void)
527 {
528 HANDLE key;
529 NTSTATUS status;
530 OBJECT_ATTRIBUTES attr;
531 UNICODE_STRING ValName;
532 KEY_VALUE_BASIC_INFORMATION *basic_info;
533 KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi;
534 KEY_VALUE_FULL_INFORMATION *full_info;
535 DWORD len, expected;
536
537 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
538
539 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
540 status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr);
541 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
542
543 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
544 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
545 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
546 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
547 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
548 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
549 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
550 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
551
552 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
553 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
554 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
555 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
556 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
557 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
558 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
559 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
560 HeapFree(GetProcessHeap(), 0, basic_info);
561
562 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
563 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
564 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
565 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
566 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
567 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
568 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
569 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
570
571 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
572 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
573 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
574 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
575 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
576 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
577 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
578 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
579 HeapFree(GetProcessHeap(), 0, partial_info);
580
581 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
582 full_info = HeapAlloc(GetProcessHeap(), 0, len);
583 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
584 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
585 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
586 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
587 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
588 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
589 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
590 "NtQueryValueKey returned wrong len %d\n", len);
591 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
592
593 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
594 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
595 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
596 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
597 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
598 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
599 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
600 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
601 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
602 *(DWORD *)((char *)full_info + full_info->DataOffset));
603 HeapFree(GetProcessHeap(), 0, full_info);
604
605 pRtlFreeUnicodeString(&ValName);
606 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
607
608 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
609 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
610 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
611 memset(partial_info, 0xbd, len+1);
612 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
613 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
614 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
615 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
616 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
617 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
618 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
619
620 expected = len;
621 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
622 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
623 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
624 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
625 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
626 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
627 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
628 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
629 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
630 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
631 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
632 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
633
634 HeapFree(GetProcessHeap(), 0, partial_info);
635 pRtlFreeUnicodeString(&ValName);
636
637 pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest");
638 status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0);
639 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
640
641 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
642 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
643 ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type);
644 ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength);
645 pRtlFreeUnicodeString(&ValName);
646
647 pNtClose(key);
648 }
649
650 static void test_NtDeleteKey(void)
651 {
652 NTSTATUS status;
653 HANDLE hkey;
654 OBJECT_ATTRIBUTES attr;
655 ACCESS_MASK am = KEY_ALL_ACCESS;
656
657 status = pNtDeleteKey(NULL);
658 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
659
660 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
661 status = pNtOpenKey(&hkey, am, &attr);
662 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
663
664 status = pNtDeleteKey(hkey);
665 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
666 }
667
668 static void test_NtQueryLicenseKey(void)
669 {
670 static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
671 UNICODE_STRING name;
672 WORD buffer[32];
673 NTSTATUS status;
674 ULONG type, len;
675 DWORD value;
676
677 if (!pNtQueryLicenseValue)
678 {
679 win_skip("NtQueryLicenseValue not found, skipping tests\n");
680 return;
681 }
682
683 type = 0xdead;
684 len = 0xbeef;
685 memset(&name, 0, sizeof(name));
686 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
687 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
688 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
689 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
690
691 /* test with empty key */
692 pRtlCreateUnicodeStringFromAsciiz(&name, "");
693
694 type = 0xdead;
695 len = 0xbeef;
696 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
697 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
698 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
699 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
700
701 type = 0xdead;
702 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
703 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
704 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
705
706 len = 0xbeef;
707 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
708 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
709 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
710
711 type = 0xdead;
712 len = 0xbeef;
713 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
714 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
715 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
716 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
717
718 pRtlFreeUnicodeString(&name);
719
720 /* test with nonexistent licence key */
721 pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
722
723 type = 0xdead;
724 len = 0xbeef;
725 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
726 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
727 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
728 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
729
730 type = 0xdead;
731 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
732 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
733 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
734
735 len = 0xbeef;
736 status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
737 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
738 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
739
740 type = 0xdead;
741 len = 0xbeef;
742 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
743 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n");
744 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
745 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
746
747 pRtlFreeUnicodeString(&name);
748
749 /* test with REG_SZ license key */
750 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
751
752 type = 0xdead;
753 len = 0xbeef;
754 status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
755 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
756 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
757 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
758
759 type = 0xdead;
760 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
761 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
762 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
763
764 type = 0xdead;
765 len = 0;
766 status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
767 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
768 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
769 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
770
771 len = 0;
772 status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
773 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
774 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
775
776 type = 0xdead;
777 len = 0;
778 memset(buffer, 0x11, sizeof(buffer));
779 status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
780 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
781 ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
782 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
783 ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
784
785 type = 0xdead;
786 len = 0;
787 memset(buffer, 0x11, sizeof(buffer));
788 status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
789 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
790 ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
791 ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
792 ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
793
794 pRtlFreeUnicodeString(&name);
795
796 /* test with REG_DWORD license key */
797 pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
798
799 type = 0xdead;
800 len = 0xbeef;
801 status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
802 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
803 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
804 ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
805
806 type = 0xdead;
807 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
808 ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
809 ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
810
811 type = 0xdead;
812 len = 0;
813 status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
814 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
815 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
816 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
817
818 len = 0;
819 status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
820 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
821 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
822
823 type = 0xdead;
824 len = 0;
825 value = 0xdeadbeef;
826 status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
827 ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
828 ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
829 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
830 ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
831
832 type = 0xdead;
833 len = 0;
834 status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
835 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
836 ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
837 ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
838
839 pRtlFreeUnicodeString(&name);
840 }
841
842 static void test_RtlpNtQueryValueKey(void)
843 {
844 NTSTATUS status;
845
846 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
847 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
848 }
849
850 static void test_symlinks(void)
851 {
852 static const WCHAR linkW[] = {'l','i','n','k',0};
853 static const WCHAR valueW[] = {'v','a','l','u','e',0};
854 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
855 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
856 static UNICODE_STRING null_str;
857 char buffer[1024];
858 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
859 WCHAR *target;
860 UNICODE_STRING symlink_str, link_str, target_str, value_str;
861 HANDLE root, key, link;
862 OBJECT_ATTRIBUTES attr;
863 NTSTATUS status;
864 DWORD target_len, len, dw;
865
866 pRtlInitUnicodeString( &link_str, linkW );
867 pRtlInitUnicodeString( &symlink_str, symlinkW );
868 pRtlInitUnicodeString( &target_str, targetW + 1 );
869 pRtlInitUnicodeString( &value_str, valueW );
870
871 target_len = winetestpath.Length + sizeof(targetW);
872 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
873 memcpy( target, winetestpath.Buffer, winetestpath.Length );
874 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
875
876 attr.Length = sizeof(attr);
877 attr.RootDirectory = 0;
878 attr.Attributes = 0;
879 attr.ObjectName = &winetestpath;
880 attr.SecurityDescriptor = NULL;
881 attr.SecurityQualityOfService = NULL;
882
883 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
884 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
885
886 attr.RootDirectory = root;
887 attr.ObjectName = &link_str;
888 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
889 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
890
891 /* REG_SZ is not allowed */
892 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
893 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
894 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
895 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
896 /* other values are not allowed */
897 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
898 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
899
900 /* try opening the target through the link */
901
902 attr.ObjectName = &link_str;
903 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
904 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
905
906 attr.ObjectName = &target_str;
907 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
908 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
909
910 dw = 0xbeef;
911 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
912 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
913 pNtClose( key );
914
915 attr.ObjectName = &link_str;
916 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
917 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
918
919 len = sizeof(buffer);
920 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
921 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
922 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
923
924 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
925 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
926
927 /* REG_LINK can be created in non-link keys */
928 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
929 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
930 len = sizeof(buffer);
931 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
932 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
933 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
934 "wrong len %u\n", len );
935 status = pNtDeleteValueKey( key, &symlink_str );
936 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
937
938 pNtClose( key );
939
940 attr.Attributes = 0;
941 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
942 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
943
944 len = sizeof(buffer);
945 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
946 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
947 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
948
949 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
950 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
951 pNtClose( key );
952
953 /* now open the symlink itself */
954
955 attr.RootDirectory = root;
956 attr.Attributes = OBJ_OPENLINK;
957 attr.ObjectName = &link_str;
958 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
959 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
960
961 len = sizeof(buffer);
962 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
963 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
964 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
965 "wrong len %u\n", len );
966 pNtClose( key );
967
968 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
969 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
970 len = sizeof(buffer);
971 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
972 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
973 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
974 "wrong len %u\n", len );
975 pNtClose( key );
976
977 if (0) /* crashes the Windows kernel on some Vista systems */
978 {
979 /* reopen the link from itself */
980
981 attr.RootDirectory = link;
982 attr.Attributes = OBJ_OPENLINK;
983 attr.ObjectName = &null_str;
984 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
985 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
986 len = sizeof(buffer);
987 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
988 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
989 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
990 "wrong len %u\n", len );
991 pNtClose( key );
992
993 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
994 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
995 len = sizeof(buffer);
996 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
997 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
998 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
999 "wrong len %u\n", len );
1000 pNtClose( key );
1001 }
1002
1003 if (0) /* crashes the Windows kernel in most versions */
1004 {
1005 attr.RootDirectory = link;
1006 attr.Attributes = 0;
1007 attr.ObjectName = &null_str;
1008 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1009 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1010 len = sizeof(buffer);
1011 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1012 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1013 pNtClose( key );
1014
1015 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1016 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1017 len = sizeof(buffer);
1018 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
1019 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
1020 pNtClose( key );
1021 }
1022
1023 /* target with terminating null doesn't work */
1024 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
1025 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1026 attr.RootDirectory = root;
1027 attr.Attributes = 0;
1028 attr.ObjectName = &link_str;
1029 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1030 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
1031
1032 /* relative symlink, works only on win2k */
1033 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
1034 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1035 attr.ObjectName = &link_str;
1036 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1037 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
1038 "NtOpenKey wrong status 0x%08x\n", status );
1039
1040 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1041 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
1042
1043 status = pNtDeleteKey( link );
1044 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1045 pNtClose( link );
1046
1047 attr.ObjectName = &target_str;
1048 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1049 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1050 status = pNtDeleteKey( key );
1051 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1052 pNtClose( key );
1053
1054 /* symlink loop */
1055
1056 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
1057 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1058 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
1059 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
1060 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
1061 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1062
1063 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1064 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
1065 "NtOpenKey failed: 0x%08x\n", status );
1066
1067 attr.Attributes = OBJ_OPENLINK;
1068 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
1069 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
1070 pNtClose( key );
1071
1072 status = pNtDeleteKey( link );
1073 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1074 pNtClose( link );
1075
1076 status = pNtDeleteKey( root );
1077 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1078 pNtClose( root );
1079
1080 pRtlFreeHeap(GetProcessHeap(), 0, target);
1081 }
1082
1083 static WCHAR valueW[] = {'v','a','l','u','e'};
1084 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
1085 static const DWORD ptr_size = 8 * sizeof(void*);
1086
1087 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
1088 {
1089 char tmp[32];
1090 NTSTATUS status;
1091 OBJECT_ATTRIBUTES attr;
1092 UNICODE_STRING str;
1093 HANDLE key;
1094 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
1095 DWORD dw, len = sizeof(tmp);
1096
1097 attr.Length = sizeof(attr);
1098 attr.RootDirectory = root;
1099 attr.Attributes = OBJ_CASE_INSENSITIVE;
1100 attr.ObjectName = &str;
1101 attr.SecurityDescriptor = NULL;
1102 attr.SecurityQualityOfService = NULL;
1103 pRtlCreateUnicodeStringFromAsciiz( &str, name );
1104
1105 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1106 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
1107 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
1108
1109 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
1110 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1111 dw = 0;
1112 else
1113 {
1114 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
1115 dw = *(DWORD *)info->Data;
1116 }
1117 pNtClose( key );
1118 pRtlFreeUnicodeString( &str );
1119 return dw;
1120 }
1121
1122 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
1123 {
1124 DWORD dw = get_key_value( root, name, flags );
1125 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
1126 }
1127 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
1128
1129 static void test_redirection(void)
1130 {
1131 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1132 'M','a','c','h','i','n','e','\\',
1133 'S','o','f','t','w','a','r','e',0};
1134 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
1135 'M','a','c','h','i','n','e','\\',
1136 'S','o','f','t','w','a','r','e','\\',
1137 'W','o','w','6','4','3','2','N','o','d','e',0};
1138 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1139 'M','a','c','h','i','n','e','\\',
1140 'S','o','f','t','w','a','r','e','\\',
1141 'W','i','n','e',0};
1142 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1143 'M','a','c','h','i','n','e','\\',
1144 'S','o','f','t','w','a','r','e','\\',
1145 'W','o','w','6','4','3','2','N','o','d','e','\\',
1146 'W','i','n','e',0};
1147 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1148 'M','a','c','h','i','n','e','\\',
1149 'S','o','f','t','w','a','r','e','\\',
1150 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
1151 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1152 'M','a','c','h','i','n','e','\\',
1153 'S','o','f','t','w','a','r','e','\\',
1154 'W','o','w','6','4','3','2','N','o','d','e','\\',
1155 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
1156 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1157 'M','a','c','h','i','n','e','\\',
1158 'S','o','f','t','w','a','r','e','\\',
1159 'C','l','a','s','s','e','s','\\',
1160 'W','i','n','e',0};
1161 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
1162 'M','a','c','h','i','n','e','\\',
1163 'S','o','f','t','w','a','r','e','\\',
1164 'C','l','a','s','s','e','s','\\',
1165 'W','o','w','6','4','3','2','N','o','d','e','\\',
1166 'W','i','n','e',0};
1167 NTSTATUS status;
1168 OBJECT_ATTRIBUTES attr;
1169 UNICODE_STRING str;
1170 char buffer[1024];
1171 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1172 DWORD dw, len;
1173 HANDLE key, root32, root64, key32, key64;
1174 BOOL is_vista = FALSE;
1175
1176 if (ptr_size != 64)
1177 {
1178 ULONG is_wow64, len;
1179 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
1180 &is_wow64, sizeof(is_wow64), &len ) ||
1181 !is_wow64)
1182 {
1183 trace( "Not on Wow64, no redirection\n" );
1184 return;
1185 }
1186 }
1187
1188 attr.Length = sizeof(attr);
1189 attr.RootDirectory = 0;
1190 attr.Attributes = OBJ_CASE_INSENSITIVE;
1191 attr.ObjectName = &str;
1192 attr.SecurityDescriptor = NULL;
1193 attr.SecurityQualityOfService = NULL;
1194
1195 pRtlInitUnicodeString( &str, wine64W );
1196 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1197 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1198
1199 pRtlInitUnicodeString( &str, wine32W );
1200 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1201 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1202
1203 pRtlInitUnicodeString( &str, key64W );
1204 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1205 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1206
1207 pRtlInitUnicodeString( &str, key32W );
1208 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1209 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1210
1211 dw = 64;
1212 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1213 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1214
1215 dw = 32;
1216 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1217 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1218
1219 len = sizeof(buffer);
1220 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1221 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1222 dw = *(DWORD *)info->Data;
1223 ok( dw == 32, "wrong value %u\n", dw );
1224
1225 len = sizeof(buffer);
1226 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1227 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1228 dw = *(DWORD *)info->Data;
1229 ok( dw == 64, "wrong value %u\n", dw );
1230
1231 pRtlInitUnicodeString( &str, softwareW );
1232 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1233 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1234
1235 if (ptr_size == 32)
1236 {
1237 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1238 /* the new (and simpler) Win7 mechanism doesn't */
1239 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1240 {
1241 trace( "using Vista-style Wow6432Node handling\n" );
1242 is_vista = TRUE;
1243 }
1244 check_key_value( key, "Wine\\Winetest", 0, 32 );
1245 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1246 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1247 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1248 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1249 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1250 }
1251 else
1252 {
1253 check_key_value( key, "Wine\\Winetest", 0, 64 );
1254 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1255 }
1256 pNtClose( key );
1257
1258 if (ptr_size == 32)
1259 {
1260 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1261 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1262 dw = get_key_value( key, "Wine\\Winetest", 0 );
1263 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1264 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1265 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1266 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1267 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1268 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1269 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1270 pNtClose( key );
1271
1272 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1273 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1274 check_key_value( key, "Wine\\Winetest", 0, 32 );
1275 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1276 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1277 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1278 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1279 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1280 pNtClose( key );
1281 }
1282
1283 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1284 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1285 if (ptr_size == 64)
1286 {
1287 /* KEY_WOW64 flags have no effect on 64-bit */
1288 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1289 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1290 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1291 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1292 }
1293 else
1294 {
1295 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1296 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1297 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1298 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1299 }
1300
1301 pRtlInitUnicodeString( &str, wownodeW );
1302 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1303 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1304 check_key_value( key, "Wine\\Winetest", 0, 32 );
1305 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1306 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1307 pNtClose( key );
1308
1309 if (ptr_size == 32)
1310 {
1311 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1312 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1313 dw = get_key_value( key, "Wine\\Winetest", 0 );
1314 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1315 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1316 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1317 pNtClose( key );
1318
1319 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1320 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1321 check_key_value( key, "Wine\\Winetest", 0, 32 );
1322 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1323 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1324 pNtClose( key );
1325 }
1326
1327 pRtlInitUnicodeString( &str, wine32W );
1328 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1329 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1330 check_key_value( key, "Winetest", 0, 32 );
1331 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1332 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1333 pNtClose( key );
1334
1335 if (ptr_size == 32)
1336 {
1337 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1338 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1339 dw = get_key_value( key, "Winetest", 0 );
1340 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1341 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1342 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1343 pNtClose( key );
1344
1345 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1346 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1347 check_key_value( key, "Winetest", 0, 32 );
1348 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1349 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1350 pNtClose( key );
1351 }
1352
1353 pRtlInitUnicodeString( &str, wine64W );
1354 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1355 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1356 check_key_value( key, "Winetest", 0, ptr_size );
1357 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1358 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1359 pNtClose( key );
1360
1361 if (ptr_size == 32)
1362 {
1363 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1364 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1365 dw = get_key_value( key, "Winetest", 0 );
1366 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1367 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1368 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1369 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1370 pNtClose( key );
1371
1372 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1373 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1374 check_key_value( key, "Winetest", 0, 32 );
1375 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1376 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1377 pNtClose( key );
1378 }
1379
1380 status = pNtDeleteKey( key32 );
1381 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1382 pNtClose( key32 );
1383
1384 status = pNtDeleteKey( key64 );
1385 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1386 pNtClose( key64 );
1387
1388 pNtDeleteKey( root32 );
1389 pNtClose( root32 );
1390 pNtDeleteKey( root64 );
1391 pNtClose( root64 );
1392
1393 /* Software\Classes is shared/reflected so behavior is different */
1394
1395 pRtlInitUnicodeString( &str, classes64W );
1396 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1397 if (status == STATUS_ACCESS_DENIED)
1398 {
1399 skip("Not authorized to modify the Classes key\n");
1400 return;
1401 }
1402 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1403
1404 pRtlInitUnicodeString( &str, classes32W );
1405 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1406 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1407
1408 dw = 64;
1409 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1410 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1411 pNtClose( key64 );
1412
1413 dw = 32;
1414 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1415 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1416 pNtClose( key32 );
1417
1418 pRtlInitUnicodeString( &str, classes64W );
1419 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1420 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1421 len = sizeof(buffer);
1422 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1423 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1424 dw = *(DWORD *)info->Data;
1425 ok( dw == ptr_size, "wrong value %u\n", dw );
1426
1427 pRtlInitUnicodeString( &str, classes32W );
1428 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1429 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1430 len = sizeof(buffer);
1431 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1432 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1433 dw = *(DWORD *)info->Data;
1434 ok( dw == 32, "wrong value %u\n", dw );
1435
1436 pNtDeleteKey( key32 );
1437 pNtClose( key32 );
1438 pNtDeleteKey( key64 );
1439 pNtClose( key64 );
1440 }
1441
1442 static void test_long_value_name(void)
1443 {
1444 HANDLE key;
1445 NTSTATUS status, expected;
1446 OBJECT_ATTRIBUTES attr;
1447 UNICODE_STRING ValName;
1448 DWORD i;
1449
1450 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1451 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1452 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1453
1454 ValName.MaximumLength = 0xfffc;
1455 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1456 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1457 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1458 ValName.Buffer[i] = 'a';
1459 ValName.Buffer[i] = 0;
1460
1461 status = pNtDeleteValueKey(key, &ValName);
1462 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1463 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1464 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1465 "NtSetValueKey with long value name returned 0x%08x\n", status);
1466 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1467 status = pNtDeleteValueKey(key, &ValName);
1468 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1469
1470 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1471 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1472
1473 pRtlFreeUnicodeString(&ValName);
1474 pNtClose(key);
1475 }
1476
1477 static void test_NtQueryKey(void)
1478 {
1479 HANDLE key, subkey, subkey2;
1480 NTSTATUS status;
1481 OBJECT_ATTRIBUTES attr;
1482 ULONG length, len;
1483 KEY_NAME_INFORMATION *info = NULL;
1484 KEY_CACHED_INFORMATION cached_info;
1485 UNICODE_STRING str;
1486 DWORD dw;
1487
1488 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1489 status = pNtOpenKey(&key, KEY_READ, &attr);
1490 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1491
1492 status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
1493 if (status == STATUS_INVALID_PARAMETER) {
1494 win_skip("KeyNameInformation is not supported\n");
1495 pNtClose(key);
1496 return;
1497 }
1498 todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
1499 info = HeapAlloc(GetProcessHeap(), 0, length);
1500
1501 /* non-zero buffer size, but insufficient */
1502 status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
1503 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
1504 ok(length == len, "got %d, expected %d\n", len, length);
1505 ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
1506 info->NameLength, winetestpath.Length);
1507
1508 /* correct buffer size */
1509 status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
1510 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1511 ok(length == len, "got %d, expected %d\n", len, length);
1512
1513 str.Buffer = info->Name;
1514 str.Length = info->NameLength;
1515 ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
1516 "got %s, expected %s\n",
1517 wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
1518 wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
1519
1520 HeapFree(GetProcessHeap(), 0, info);
1521
1522 attr.RootDirectory = key;
1523 attr.ObjectName = &str;
1524 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1525 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1526 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1527
1528 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1529 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1530
1531 if (status == STATUS_SUCCESS)
1532 {
1533 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1534 ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1535 ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1536 ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
1537 ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1538 ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1539 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1540 }
1541
1542 attr.RootDirectory = subkey;
1543 attr.ObjectName = &str;
1544 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
1545 status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
1546 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1547
1548 pRtlCreateUnicodeStringFromAsciiz(&str, "val");
1549 dw = 64;
1550 status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
1551 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1552
1553 if (!winetest_interactive)
1554 skip("ROSTESTS-198: Causes an assert in Cm.\n");
1555 else
1556 {
1557 status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
1558 ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
1559
1560 if (status == STATUS_SUCCESS)
1561 {
1562 ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
1563 ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
1564 ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
1565 ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
1566 ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
1567 ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
1568 ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
1569 }
1570 }
1571
1572 status = pNtDeleteKey(subkey2);
1573 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1574 status = pNtDeleteKey(subkey);
1575 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1576
1577 pNtClose(subkey2);
1578 pNtClose(subkey);
1579 pNtClose(key);
1580 }
1581
1582 static void test_notify(void)
1583 {
1584 OBJECT_ATTRIBUTES attr;
1585 LARGE_INTEGER timeout;
1586 IO_STATUS_BLOCK iosb;
1587 UNICODE_STRING str;
1588 HANDLE key, events[2], subkey;
1589 NTSTATUS status;
1590
1591 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1592 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1593 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1594
1595 events[0] = CreateEventW(NULL, FALSE, TRUE, NULL);
1596 ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError());
1597 events[1] = CreateEventW(NULL, FALSE, TRUE, NULL);
1598 ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError());
1599
1600 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1601 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1602 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1603 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1604
1605 timeout.QuadPart = 0;
1606 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1607 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1608 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1609 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1610
1611 attr.RootDirectory = key;
1612 attr.ObjectName = &str;
1613
1614 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1615 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1616 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1617
1618 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1619 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1620 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1621 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1622
1623 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1624 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1625 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1626 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1627
1628 status = pNtDeleteKey(subkey);
1629 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1630
1631 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1632 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1633 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1634 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1635
1636 pNtClose(subkey);
1637
1638 status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1639 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1640 status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
1641 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1642
1643 pNtClose(key);
1644
1645 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1646 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1647 status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
1648 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1649
1650 if (pNtNotifyChangeMultipleKeys)
1651 {
1652 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1653 status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
1654 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1655
1656 status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
1657 ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status);
1658
1659 timeout.QuadPart = 0;
1660 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1661 ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status);
1662
1663 attr.RootDirectory = key;
1664 attr.ObjectName = &str;
1665 pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
1666 status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
1667 ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
1668
1669 status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
1670 ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
1671
1672 status = pNtDeleteKey(subkey);
1673 ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
1674 pNtClose(subkey);
1675 pNtClose(key);
1676 }
1677 else
1678 {
1679 win_skip("NtNotifyChangeMultipleKeys not available\n");
1680 }
1681
1682 pNtClose(events[0]);
1683 pNtClose(events[1]);
1684 }
1685
1686 START_TEST(reg)
1687 {
1688 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1689 if(!InitFunctionPtrs())
1690 return;
1691 pRtlFormatCurrentUserKeyPath(&winetestpath);
1692 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1693 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1694 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1695
1696 pRtlAppendUnicodeToString(&winetestpath, winetest);
1697
1698 test_NtCreateKey();
1699 test_NtOpenKey();
1700 test_NtSetValueKey();
1701 test_RtlCheckRegistryKey();
1702 test_RtlOpenCurrentUser();
1703 test_RtlQueryRegistryValues();
1704 test_RtlpNtQueryValueKey();
1705 test_NtFlushKey();
1706 test_NtQueryKey();
1707 test_NtQueryLicenseKey();
1708 test_NtQueryValueKey();
1709 test_long_value_name();
1710 test_notify();
1711 test_NtDeleteKey();
1712 test_symlinks();
1713 test_redirection();
1714
1715 pRtlFreeUnicodeString(&winetestpath);
1716
1717 FreeLibrary(hntdll);
1718 }