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