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 } 1894