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