[NTDLL_WINETEST]
[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 || status == STATUS_ACCESS_DENIED /* Win7 */,
400 "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
401
402 /* Length > sizeof(OBJECT_ATTRIBUTES) */
403 attr.Length *= 2;
404 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
405 ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status);
406
407 attr.Length = sizeof(attr);
408 status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
409 ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status);
410
411 attr.RootDirectory = key;
412 attr.ObjectName = &str;
413
414 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" );
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_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
422 pRtlFreeUnicodeString( &str );
423
424 pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" );
425 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
426 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status );
427 pRtlFreeUnicodeString( &str );
428
429 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" );
430 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
431 ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */
432 "NtCreateKey failed: 0x%08x\n", status );
433 if (status == STATUS_SUCCESS)
434 {
435 pNtDeleteKey( subkey );
436 pNtClose( subkey );
437 }
438 pRtlFreeUnicodeString( &str );
439
440 pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" );
441 status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
442 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
443 pRtlFreeUnicodeString( &str );
444 pNtDeleteKey( subkey );
445 pNtClose( subkey );
446
447 pNtClose(key);
448 }
449
450 static void test_NtSetValueKey(void)
451 {
452 HANDLE key;
453 NTSTATUS status;
454 OBJECT_ATTRIBUTES attr;
455 ACCESS_MASK am = KEY_WRITE;
456 UNICODE_STRING ValName;
457 DWORD data = 711;
458
459 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
460 status = pNtOpenKey(&key, am, &attr);
461 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
462
463 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
464 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
465 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
466 pRtlFreeUnicodeString(&ValName);
467
468 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
469 status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE);
470 ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status);
471 pRtlFreeUnicodeString(&ValName);
472
473 pNtClose(key);
474 }
475
476 static void test_RtlOpenCurrentUser(void)
477 {
478 NTSTATUS status;
479 HANDLE handle;
480 status=pRtlOpenCurrentUser(KEY_READ, &handle);
481 ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status);
482 pNtClose(handle);
483 }
484
485 static void test_RtlCheckRegistryKey(void)
486 {
487 NTSTATUS status;
488
489 status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
490 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status);
491
492 status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer);
493 ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status);
494 }
495
496 static void test_NtFlushKey(void)
497 {
498 NTSTATUS status;
499 HANDLE hkey;
500 OBJECT_ATTRIBUTES attr;
501 ACCESS_MASK am = KEY_ALL_ACCESS;
502
503 status = pNtFlushKey(NULL);
504 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
505
506 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
507 pNtOpenKey(&hkey, am, &attr);
508
509 status = pNtFlushKey(hkey);
510 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
511
512 pNtClose(hkey);
513 }
514
515 static void test_NtQueryValueKey(void)
516 {
517 HANDLE key;
518 NTSTATUS status;
519 OBJECT_ATTRIBUTES attr;
520 UNICODE_STRING ValName;
521 KEY_VALUE_BASIC_INFORMATION *basic_info;
522 KEY_VALUE_PARTIAL_INFORMATION *partial_info;
523 KEY_VALUE_FULL_INFORMATION *full_info;
524 DWORD len, expected;
525
526 pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
527
528 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
529 status = pNtOpenKey(&key, KEY_READ, &attr);
530 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
531
532 len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
533 basic_info = HeapAlloc(GetProcessHeap(), 0, len);
534 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
535 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
536 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
537 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
538 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
539 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
540
541 basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len);
542 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
543 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
544 ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex);
545 ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type);
546 ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength);
547 ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len);
548 ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
549 HeapFree(GetProcessHeap(), 0, basic_info);
550
551 len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
552 partial_info = HeapAlloc(GetProcessHeap(), 0, len);
553 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
554 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
555 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
556 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
557 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
558 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
559
560 partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len);
561 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
562 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
563 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
564 ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
565 ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
566 ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len);
567 ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data);
568 HeapFree(GetProcessHeap(), 0, partial_info);
569
570 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
571 full_info = HeapAlloc(GetProcessHeap(), 0, len);
572 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
573 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status);
574 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
575 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
576 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
577 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
578 ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
579 "NtQueryValueKey returned wrong len %d\n", len);
580 len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength;
581
582 full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len);
583 status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
584 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
585 ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex);
586 ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type);
587 ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength);
588 ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength);
589 ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n");
590 ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n",
591 *(DWORD *)((char *)full_info + full_info->DataOffset));
592 HeapFree(GetProcessHeap(), 0, full_info);
593
594 pRtlFreeUnicodeString(&ValName);
595 pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest");
596
597 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len);
598 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status);
599 partial_info = HeapAlloc(GetProcessHeap(), 0, len+1);
600 memset(partial_info, 0xbd, len+1);
601 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
602 ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status);
603 ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex);
604 ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type);
605 ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength);
606 ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n");
607 ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE));
608
609 expected = len;
610 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len);
611 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
612 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
613 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
614 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
615 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
616 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len);
617 ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status);
618 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
619 status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len);
620 ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status);
621 ok(len == expected, "NtQueryValueKey wrong len %u\n", len);
622
623 HeapFree(GetProcessHeap(), 0, partial_info);
624
625 pRtlFreeUnicodeString(&ValName);
626 pNtClose(key);
627 }
628
629 static void test_NtDeleteKey(void)
630 {
631 NTSTATUS status;
632 HANDLE hkey;
633 OBJECT_ATTRIBUTES attr;
634 ACCESS_MASK am = KEY_ALL_ACCESS;
635
636 status = pNtDeleteKey(NULL);
637 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
638
639 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
640 status = pNtOpenKey(&hkey, am, &attr);
641 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
642
643 status = pNtDeleteKey(hkey);
644 ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
645 }
646
647 static void test_RtlpNtQueryValueKey(void)
648 {
649 NTSTATUS status;
650
651 status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL);
652 ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status);
653 }
654
655 static void test_symlinks(void)
656 {
657 static const WCHAR linkW[] = {'l','i','n','k',0};
658 static const WCHAR valueW[] = {'v','a','l','u','e',0};
659 static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
660 static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
661 static UNICODE_STRING null_str;
662 char buffer[1024];
663 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
664 WCHAR *target;
665 UNICODE_STRING symlink_str, link_str, target_str, value_str;
666 HANDLE root, key, link;
667 OBJECT_ATTRIBUTES attr;
668 NTSTATUS status;
669 DWORD target_len, len, dw;
670
671 pRtlInitUnicodeString( &link_str, linkW );
672 pRtlInitUnicodeString( &symlink_str, symlinkW );
673 pRtlInitUnicodeString( &target_str, targetW + 1 );
674 pRtlInitUnicodeString( &value_str, valueW );
675
676 target_len = winetestpath.Length + sizeof(targetW);
677 target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ );
678 memcpy( target, winetestpath.Buffer, winetestpath.Length );
679 memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) );
680
681 attr.Length = sizeof(attr);
682 attr.RootDirectory = 0;
683 attr.Attributes = 0;
684 attr.ObjectName = &winetestpath;
685 attr.SecurityDescriptor = NULL;
686 attr.SecurityQualityOfService = NULL;
687
688 status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
689 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
690
691 attr.RootDirectory = root;
692 attr.ObjectName = &link_str;
693 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
694 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
695
696 /* REG_SZ is not allowed */
697 status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len );
698 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
699 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
700 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
701 /* other values are not allowed */
702 status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
703 ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status );
704
705 /* try opening the target through the link */
706
707 attr.ObjectName = &link_str;
708 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
709 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
710
711 attr.ObjectName = &target_str;
712 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
713 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
714
715 dw = 0xbeef;
716 status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
717 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
718 pNtClose( key );
719
720 attr.ObjectName = &link_str;
721 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
722 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
723
724 len = sizeof(buffer);
725 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
726 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
727 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
728
729 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
730 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
731
732 /* REG_LINK can be created in non-link keys */
733 status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
734 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
735 len = sizeof(buffer);
736 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
737 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
738 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
739 "wrong len %u\n", len );
740 status = pNtDeleteValueKey( key, &symlink_str );
741 ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status );
742
743 pNtClose( key );
744
745 attr.Attributes = 0;
746 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
747 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
748
749 len = sizeof(buffer);
750 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
751 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
752 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len );
753
754 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
755 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
756 pNtClose( key );
757
758 /* now open the symlink itself */
759
760 attr.RootDirectory = root;
761 attr.Attributes = OBJ_OPENLINK;
762 attr.ObjectName = &link_str;
763 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
764 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
765
766 len = sizeof(buffer);
767 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
768 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
769 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
770 "wrong len %u\n", len );
771 pNtClose( key );
772
773 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
774 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
775 len = sizeof(buffer);
776 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
777 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
778 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
779 "wrong len %u\n", len );
780 pNtClose( key );
781
782 if (0) /* crashes the Windows kernel on some Vista systems */
783 {
784 /* reopen the link from itself */
785
786 attr.RootDirectory = link;
787 attr.Attributes = OBJ_OPENLINK;
788 attr.ObjectName = &null_str;
789 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
790 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
791 len = sizeof(buffer);
792 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
793 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
794 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
795 "wrong len %u\n", len );
796 pNtClose( key );
797
798 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
799 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
800 len = sizeof(buffer);
801 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
802 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
803 ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
804 "wrong len %u\n", len );
805 pNtClose( key );
806 }
807
808 if (0) /* crashes the Windows kernel in most versions */
809 {
810 attr.RootDirectory = link;
811 attr.Attributes = 0;
812 attr.ObjectName = &null_str;
813 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
814 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
815 len = sizeof(buffer);
816 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
817 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
818 pNtClose( key );
819
820 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
821 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
822 len = sizeof(buffer);
823 status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
824 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
825 pNtClose( key );
826 }
827
828 /* target with terminating null doesn't work */
829 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len );
830 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
831 attr.RootDirectory = root;
832 attr.Attributes = 0;
833 attr.ObjectName = &link_str;
834 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
835 ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
836
837 /* relative symlink, works only on win2k */
838 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) );
839 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
840 attr.ObjectName = &link_str;
841 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
842 ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
843 "NtOpenKey wrong status 0x%08x\n", status );
844
845 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
846 ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
847
848 status = pNtDeleteKey( link );
849 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
850 pNtClose( link );
851
852 attr.ObjectName = &target_str;
853 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
854 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
855 status = pNtDeleteKey( key );
856 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
857 pNtClose( key );
858
859 /* symlink loop */
860
861 status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
862 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
863 memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) );
864 status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK,
865 target, target_len + sizeof(targetW) - sizeof(WCHAR) );
866 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
867
868 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
869 ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG,
870 "NtOpenKey failed: 0x%08x\n", status );
871
872 attr.Attributes = OBJ_OPENLINK;
873 status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
874 ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
875 pNtClose( key );
876
877 status = pNtDeleteKey( link );
878 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
879 pNtClose( link );
880
881 status = pNtDeleteKey( root );
882 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
883 pNtClose( root );
884
885 pRtlFreeHeap(GetProcessHeap(), 0, target);
886 }
887
888 static WCHAR valueW[] = {'v','a','l','u','e'};
889 static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW };
890 static const DWORD ptr_size = 8 * sizeof(void*);
891
892 static DWORD get_key_value( HANDLE root, const char *name, DWORD flags )
893 {
894 char tmp[32];
895 NTSTATUS status;
896 OBJECT_ATTRIBUTES attr;
897 UNICODE_STRING str;
898 HANDLE key;
899 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp;
900 DWORD dw, len = sizeof(tmp);
901
902 attr.Length = sizeof(attr);
903 attr.RootDirectory = root;
904 attr.Attributes = OBJ_CASE_INSENSITIVE;
905 attr.ObjectName = &str;
906 attr.SecurityDescriptor = NULL;
907 attr.SecurityQualityOfService = NULL;
908 pRtlCreateUnicodeStringFromAsciiz( &str, name );
909
910 status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
911 if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0;
912 ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status );
913
914 status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
915 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
916 dw = 0;
917 else
918 {
919 ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status );
920 dw = *(DWORD *)info->Data;
921 }
922 pNtClose( key );
923 pRtlFreeUnicodeString( &str );
924 return dw;
925 }
926
927 static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect )
928 {
929 DWORD dw = get_key_value( root, name, flags );
930 ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect );
931 }
932 #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect )
933
934 static void test_redirection(void)
935 {
936 static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\',
937 'M','a','c','h','i','n','e','\\',
938 'S','o','f','t','w','a','r','e',0};
939 static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\',
940 'M','a','c','h','i','n','e','\\',
941 'S','o','f','t','w','a','r','e','\\',
942 'W','o','w','6','4','3','2','N','o','d','e',0};
943 static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
944 'M','a','c','h','i','n','e','\\',
945 'S','o','f','t','w','a','r','e','\\',
946 'W','i','n','e',0};
947 static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
948 'M','a','c','h','i','n','e','\\',
949 'S','o','f','t','w','a','r','e','\\',
950 'W','o','w','6','4','3','2','N','o','d','e','\\',
951 'W','i','n','e',0};
952 static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
953 'M','a','c','h','i','n','e','\\',
954 'S','o','f','t','w','a','r','e','\\',
955 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0};
956 static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
957 'M','a','c','h','i','n','e','\\',
958 'S','o','f','t','w','a','r','e','\\',
959 'W','o','w','6','4','3','2','N','o','d','e','\\',
960 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0};
961 static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\',
962 'M','a','c','h','i','n','e','\\',
963 'S','o','f','t','w','a','r','e','\\',
964 'C','l','a','s','s','e','s','\\',
965 'W','i','n','e',0};
966 static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\',
967 'M','a','c','h','i','n','e','\\',
968 'S','o','f','t','w','a','r','e','\\',
969 'C','l','a','s','s','e','s','\\',
970 'W','o','w','6','4','3','2','N','o','d','e','\\',
971 'W','i','n','e',0};
972 NTSTATUS status;
973 OBJECT_ATTRIBUTES attr;
974 UNICODE_STRING str;
975 char buffer[1024];
976 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
977 DWORD dw, len;
978 HANDLE key, root32, root64, key32, key64;
979 BOOL is_vista = FALSE;
980
981 if (ptr_size != 64)
982 {
983 ULONG is_wow64, len;
984 if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information,
985 &is_wow64, sizeof(is_wow64), &len ) ||
986 !is_wow64)
987 {
988 trace( "Not on Wow64, no redirection\n" );
989 return;
990 }
991 }
992
993 attr.Length = sizeof(attr);
994 attr.RootDirectory = 0;
995 attr.Attributes = OBJ_CASE_INSENSITIVE;
996 attr.ObjectName = &str;
997 attr.SecurityDescriptor = NULL;
998 attr.SecurityQualityOfService = NULL;
999
1000 pRtlInitUnicodeString( &str, wine64W );
1001 status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1002 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1003
1004 pRtlInitUnicodeString( &str, wine32W );
1005 status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1006 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1007
1008 pRtlInitUnicodeString( &str, key64W );
1009 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1010 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1011
1012 pRtlInitUnicodeString( &str, key32W );
1013 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1014 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1015
1016 dw = 64;
1017 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1018 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1019
1020 dw = 32;
1021 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1022 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1023
1024 len = sizeof(buffer);
1025 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1026 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1027 dw = *(DWORD *)info->Data;
1028 ok( dw == 32, "wrong value %u\n", dw );
1029
1030 len = sizeof(buffer);
1031 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1032 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1033 dw = *(DWORD *)info->Data;
1034 ok( dw == 64, "wrong value %u\n", dw );
1035
1036 pRtlInitUnicodeString( &str, softwareW );
1037 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1038 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1039
1040 if (ptr_size == 32)
1041 {
1042 /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */
1043 /* the new (and simpler) Win7 mechanism doesn't */
1044 if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32)
1045 {
1046 trace( "using Vista-style Wow6432Node handling\n" );
1047 is_vista = TRUE;
1048 }
1049 check_key_value( key, "Wine\\Winetest", 0, 32 );
1050 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1051 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1052 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1053 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1054 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1055 }
1056 else
1057 {
1058 check_key_value( key, "Wine\\Winetest", 0, 64 );
1059 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1060 }
1061 pNtClose( key );
1062
1063 if (ptr_size == 32)
1064 {
1065 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1066 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1067 dw = get_key_value( key, "Wine\\Winetest", 0 );
1068 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1069 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1070 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1071 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 );
1072 dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY );
1073 ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw );
1074 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1075 pNtClose( key );
1076
1077 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1078 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1079 check_key_value( key, "Wine\\Winetest", 0, 32 );
1080 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1081 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1082 check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 );
1083 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 );
1084 check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 );
1085 pNtClose( key );
1086 }
1087
1088 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size );
1089 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 );
1090 if (ptr_size == 64)
1091 {
1092 /* KEY_WOW64 flags have no effect on 64-bit */
1093 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1094 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 );
1095 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 );
1096 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1097 }
1098 else
1099 {
1100 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 );
1101 check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1102 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1103 check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1104 }
1105
1106 pRtlInitUnicodeString( &str, wownodeW );
1107 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1108 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1109 check_key_value( key, "Wine\\Winetest", 0, 32 );
1110 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) );
1111 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1112 pNtClose( key );
1113
1114 if (ptr_size == 32)
1115 {
1116 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1117 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1118 dw = get_key_value( key, "Wine\\Winetest", 0 );
1119 ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1120 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1121 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1122 pNtClose( key );
1123
1124 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1125 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1126 check_key_value( key, "Wine\\Winetest", 0, 32 );
1127 check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1128 check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 );
1129 pNtClose( key );
1130 }
1131
1132 pRtlInitUnicodeString( &str, wine32W );
1133 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1134 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1135 check_key_value( key, "Winetest", 0, 32 );
1136 check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 );
1137 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1138 pNtClose( key );
1139
1140 if (ptr_size == 32)
1141 {
1142 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1143 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1144 dw = get_key_value( key, "Winetest", 0 );
1145 ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw );
1146 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1147 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1148 pNtClose( key );
1149
1150 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1151 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1152 check_key_value( key, "Winetest", 0, 32 );
1153 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1154 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1155 pNtClose( key );
1156 }
1157
1158 pRtlInitUnicodeString( &str, wine64W );
1159 status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1160 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1161 check_key_value( key, "Winetest", 0, ptr_size );
1162 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size );
1163 check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size );
1164 pNtClose( key );
1165
1166 if (ptr_size == 32)
1167 {
1168 status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1169 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1170 dw = get_key_value( key, "Winetest", 0 );
1171 ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw );
1172 check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 );
1173 dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY );
1174 todo_wine ok( dw == 32, "wrong value %u\n", dw );
1175 pNtClose( key );
1176
1177 status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1178 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1179 check_key_value( key, "Winetest", 0, 32 );
1180 check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 );
1181 check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 );
1182 pNtClose( key );
1183 }
1184
1185 status = pNtDeleteKey( key32 );
1186 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1187 pNtClose( key32 );
1188
1189 status = pNtDeleteKey( key64 );
1190 ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
1191 pNtClose( key64 );
1192
1193 pNtDeleteKey( root32 );
1194 pNtClose( root32 );
1195 pNtDeleteKey( root64 );
1196 pNtClose( root64 );
1197
1198 /* Software\Classes is shared/reflected so behavior is different */
1199
1200 pRtlInitUnicodeString( &str, classes64W );
1201 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1202 if (status == STATUS_ACCESS_DENIED)
1203 {
1204 skip("Not authorized to modify the Classes key\n");
1205 return;
1206 }
1207 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1208
1209 pRtlInitUnicodeString( &str, classes32W );
1210 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1211 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1212
1213 dw = 64;
1214 status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1215 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1216 pNtClose( key64 );
1217
1218 dw = 32;
1219 status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
1220 ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
1221 pNtClose( key32 );
1222
1223 pRtlInitUnicodeString( &str, classes64W );
1224 status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1225 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1226 len = sizeof(buffer);
1227 status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
1228 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1229 dw = *(DWORD *)info->Data;
1230 ok( dw == ptr_size, "wrong value %u\n", dw );
1231
1232 pRtlInitUnicodeString( &str, classes32W );
1233 status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
1234 ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
1235 len = sizeof(buffer);
1236 status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
1237 ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
1238 dw = *(DWORD *)info->Data;
1239 ok( dw == 32, "wrong value %u\n", dw );
1240
1241 pNtDeleteKey( key32 );
1242 pNtClose( key32 );
1243 pNtDeleteKey( key64 );
1244 pNtClose( key64 );
1245 }
1246
1247 static void test_long_value_name(void)
1248 {
1249 HANDLE key;
1250 NTSTATUS status, expected;
1251 OBJECT_ATTRIBUTES attr;
1252 UNICODE_STRING ValName;
1253 DWORD i;
1254
1255 InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
1256 status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr);
1257 ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
1258
1259 ValName.MaximumLength = 0xfffc;
1260 ValName.Length = ValName.MaximumLength - sizeof(WCHAR);
1261 ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength);
1262 for (i = 0; i < ValName.Length / sizeof(WCHAR); i++)
1263 ValName.Buffer[i] = 'a';
1264 ValName.Buffer[i] = 0;
1265
1266 status = pNtDeleteValueKey(key, &ValName);
1267 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status);
1268 status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i));
1269 ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */,
1270 "NtSetValueKey with long value name returned 0x%08x\n", status);
1271 expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
1272 status = pNtDeleteValueKey(key, &ValName);
1273 ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status);
1274
1275 status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i);
1276 ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status);
1277
1278 pRtlFreeUnicodeString(&ValName);
1279 pNtClose(key);
1280 }
1281
1282 START_TEST(reg)
1283 {
1284 static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
1285 if(!InitFunctionPtrs())
1286 return;
1287 pRtlFormatCurrentUserKeyPath(&winetestpath);
1288 winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer,
1289 winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR));
1290 winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR);
1291
1292 pRtlAppendUnicodeToString(&winetestpath, winetest);
1293
1294 test_NtCreateKey();
1295 test_NtOpenKey();
1296 test_NtSetValueKey();
1297 test_RtlCheckRegistryKey();
1298 test_RtlOpenCurrentUser();
1299 test_RtlQueryRegistryValues();
1300 test_RtlpNtQueryValueKey();
1301 test_NtFlushKey();
1302 test_NtQueryValueKey();
1303 test_long_value_name();
1304 test_NtDeleteKey();
1305 test_symlinks();
1306 test_redirection();
1307
1308 pRtlFreeUnicodeString(&winetestpath);
1309
1310 FreeLibrary(hntdll);
1311 }