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