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