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