| /* Unit test suite for Rtl* Registry API functions | |
| * | |
| * Copyright 2003 Thomas Mertes | |
| * Copyright 2005 Brad DeMorrow | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| * | |
| * NOTE: I don't test every RelativeTo value because it would be redundant, all calls go through | |
| * helper function RTL_GetKeyHandle().--Brad DeMorrow | |
| * | |
| */ | |
| #include "ntdll_test.h" | |
| #include "winternl.h" | |
| #include "stdio.h" | |
| #include "winnt.h" | |
| #include "winnls.h" | |
| #include "stdlib.h" | |
| /* A test string */ | |
| static const WCHAR stringW[] = {'s', 't', 'r', 'i', 'n', 'g', 'W', 0}; | |
| /* A size, in bytes, short enough to cause truncation of the above */ | |
| #define STR_TRUNC_SIZE (sizeof(stringW)-2*sizeof(*stringW)) | |
| #ifndef __WINE_WINTERNL_H | |
| /* RtlQueryRegistryValues structs and defines */ | |
| #define RTL_REGISTRY_ABSOLUTE 0 | |
| #define RTL_REGISTRY_SERVICES 1 | |
| #define RTL_REGISTRY_CONTROL 2 | |
| #define RTL_REGISTRY_WINDOWS_NT 3 | |
| #define RTL_REGISTRY_DEVICEMAP 4 | |
| #define RTL_REGISTRY_USER 5 | |
| #define RTL_REGISTRY_HANDLE 0x40000000 | |
| #define RTL_REGISTRY_OPTIONAL 0x80000000 | |
| #define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 | |
| #define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 | |
| #define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 | |
| #define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 | |
| #define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 | |
| #define RTL_QUERY_REGISTRY_DIRECT 0x00000020 | |
| #define RTL_QUERY_REGISTRY_DELETE 0x00000040 | |
| typedef NTSTATUS (WINAPI *PRTL_QUERY_REGISTRY_ROUTINE)( PCWSTR ValueName, | |
| ULONG ValueType, | |
| PVOID ValueData, | |
| ULONG ValueLength, | |
| PVOID Context, | |
| PVOID EntryContext); | |
| typedef struct _RTL_QUERY_REGISTRY_TABLE { | |
| PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; | |
| ULONG Flags; | |
| PWSTR Name; | |
| PVOID EntryContext; | |
| ULONG DefaultType; | |
| PVOID DefaultData; | |
| ULONG DefaultLength; | |
| } RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; | |
| typedef struct _KEY_VALUE_BASIC_INFORMATION { | |
| ULONG TitleIndex; | |
| ULONG Type; | |
| ULONG NameLength; | |
| WCHAR Name[1]; | |
| } KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; | |
| typedef struct _KEY_VALUE_PARTIAL_INFORMATION { | |
| ULONG TitleIndex; | |
| ULONG Type; | |
| ULONG DataLength; | |
| UCHAR Data[1]; | |
| } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; | |
| typedef struct _KEY_VALUE_FULL_INFORMATION { | |
| ULONG TitleIndex; | |
| ULONG Type; | |
| ULONG DataOffset; | |
| ULONG DataLength; | |
| ULONG NameLength; | |
| WCHAR Name[1]; | |
| } KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; | |
| typedef enum _KEY_VALUE_INFORMATION_CLASS { | |
| KeyValueBasicInformation, | |
| KeyValueFullInformation, | |
| KeyValuePartialInformation, | |
| KeyValueFullInformationAlign64, | |
| KeyValuePartialInformationAlign64 | |
| } KEY_VALUE_INFORMATION_CLASS; | |
| #define InitializeObjectAttributes(p,n,a,r,s) \ | |
| do { \ | |
| (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ | |
| (p)->RootDirectory = r; \ | |
| (p)->Attributes = a; \ | |
| (p)->ObjectName = n; \ | |
| (p)->SecurityDescriptor = s; \ | |
| (p)->SecurityQualityOfService = NULL; \ | |
| } while (0) | |
| #endif | |
| static BOOLEAN (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); | |
| static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR); | |
| static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING); | |
| static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING); | |
| static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_QUERY_REGISTRY_TABLE, IN PVOID,IN PVOID); | |
| static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR); | |
| static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE); | |
| static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES); | |
| static NTSTATUS (WINAPI * pNtOpenKeyEx)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); | |
| static NTSTATUS (WINAPI * pNtClose)(IN HANDLE); | |
| static NTSTATUS (WINAPI * pNtFlushKey)(HANDLE); | |
| static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE); | |
| static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, | |
| ULONG TitleIndex, const UNICODE_STRING *class, ULONG options, | |
| PULONG dispos ); | |
| static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,KEY_INFORMATION_CLASS,PVOID,ULONG,PULONG); | |
| static NTSTATUS (WINAPI * pNtQueryLicenseValue)(const UNICODE_STRING *,ULONG *,PVOID,ULONG,ULONG *); | |
| static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *); | |
| static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG, | |
| ULONG, const void*, ULONG ); | |
| static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG); | |
| static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING); | |
| static LONG (WINAPI * pRtlCompareUnicodeString)(const PUNICODE_STRING,const PUNICODE_STRING,BOOLEAN); | |
| static BOOLEAN (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR); | |
| static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG); | |
| static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR); | |
| static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL); | |
| static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID); | |
| static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG); | |
| static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG); | |
| static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *); | |
| static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN); | |
| static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE, | |
| void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN); | |
| static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*); | |
| static HMODULE hntdll = 0; | |
| static int CurrentTest = 0; | |
| static UNICODE_STRING winetestpath; | |
| #define NTDLL_GET_PROC(func) \ | |
| p ## func = (void*)GetProcAddress(hntdll, #func); \ | |
| if(!p ## func) { \ | |
| trace("GetProcAddress(%s) failed\n", #func); \ | |
| FreeLibrary(hntdll); \ | |
| return FALSE; \ | |
| } | |
| static BOOL InitFunctionPtrs(void) | |
| { | |
| hntdll = LoadLibraryA("ntdll.dll"); | |
| if(!hntdll) { | |
| trace("Could not load ntdll.dll\n"); | |
| return FALSE; | |
| } | |
| NTDLL_GET_PROC(RtlInitUnicodeString) | |
| NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz) | |
| NTDLL_GET_PROC(RtlCreateUnicodeString) | |
| NTDLL_GET_PROC(RtlFreeUnicodeString) | |
| NTDLL_GET_PROC(RtlQueryRegistryValues) | |
| NTDLL_GET_PROC(RtlCheckRegistryKey) | |
| NTDLL_GET_PROC(RtlOpenCurrentUser) | |
| NTDLL_GET_PROC(NtClose) | |
| NTDLL_GET_PROC(NtDeleteValueKey) | |
| NTDLL_GET_PROC(NtCreateKey) | |
| NTDLL_GET_PROC(NtFlushKey) | |
| NTDLL_GET_PROC(NtDeleteKey) | |
| NTDLL_GET_PROC(NtQueryKey) | |
| NTDLL_GET_PROC(NtQueryValueKey) | |
| NTDLL_GET_PROC(NtQueryInformationProcess) | |
| NTDLL_GET_PROC(NtSetValueKey) | |
| NTDLL_GET_PROC(NtOpenKey) | |
| NTDLL_GET_PROC(NtNotifyChangeKey) | |
| NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath) | |
| NTDLL_GET_PROC(RtlCompareUnicodeString) | |
| NTDLL_GET_PROC(RtlReAllocateHeap) | |
| NTDLL_GET_PROC(RtlAppendUnicodeToString) | |
| NTDLL_GET_PROC(RtlUnicodeStringToAnsiString) | |
| NTDLL_GET_PROC(RtlFreeHeap) | |
| NTDLL_GET_PROC(RtlAllocateHeap) | |
| NTDLL_GET_PROC(RtlZeroMemory) | |
| NTDLL_GET_PROC(RtlpNtQueryValueKey) | |
| NTDLL_GET_PROC(RtlOpenCurrentUser) | |
| NTDLL_GET_PROC(NtWaitForSingleObject) | |
| /* optional functions */ | |
| pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue"); | |
| pNtOpenKeyEx = (void *)GetProcAddress(hntdll, "NtOpenKeyEx"); | |
| pNtNotifyChangeMultipleKeys = (void *)GetProcAddress(hntdll, "NtNotifyChangeMultipleKeys"); | |
| return TRUE; | |
| } | |
| #undef NTDLL_GET_PROC | |
| static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, | |
| IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext) | |
| { | |
| NTSTATUS ret = STATUS_SUCCESS; | |
| trace("**Test %d**\n", CurrentTest); | |
| trace("ValueName: %s\n", wine_dbgstr_w(ValueName)); | |
| switch(ValueType) | |
| { | |
| case REG_NONE: | |
| trace("ValueType: REG_NONE\n"); | |
| trace("ValueData: %p\n", ValueData); | |
| break; | |
| case REG_BINARY: | |
| trace("ValueType: REG_BINARY\n"); | |
| trace("ValueData: %p\n", ValueData); | |
| break; | |
| case REG_SZ: | |
| trace("ValueType: REG_SZ\n"); | |
| trace("ValueData: %s\n", (char*)ValueData); | |
| break; | |
| case REG_MULTI_SZ: | |
| trace("ValueType: REG_MULTI_SZ\n"); | |
| trace("ValueData: %s\n", (char*)ValueData); | |
| break; | |
| case REG_EXPAND_SZ: | |
| trace("ValueType: REG_EXPAND_SZ\n"); | |
| trace("ValueData: %s\n", (char*)ValueData); | |
| break; | |
| case REG_DWORD: | |
| trace("ValueType: REG_DWORD\n"); | |
| trace("ValueData: %p\n", ValueData); | |
| break; | |
| }; | |
| trace("ValueLength: %d\n", (int)ValueLength); | |
| if(CurrentTest == 0) | |
| ok(1, "\n"); /*checks that QueryRoutine is called*/ | |
| if(CurrentTest > 7) | |
| ok(!1, "Invalid Test Specified!\n"); | |
| CurrentTest++; | |
| return ret; | |
| } | |
| static void test_RtlQueryRegistryValues(void) | |
| { | |
| /* | |
| ****************************** | |
| * QueryTable Flags * | |
| ****************************** | |
| *RTL_QUERY_REGISTRY_SUBKEY * Name is the name of a subkey relative to Path | |
| *RTL_QUERY_REGISTRY_TOPKEY * Resets location to original RelativeTo and Path | |
| *RTL_QUERY_REGISTRY_REQUIRED * Key required. returns STATUS_OBJECT_NAME_NOT_FOUND if not present | |
| *RTL_QUERY_REGISTRY_NOVALUE * We just want a call-back | |
| *RTL_QUERY_REGISTRY_NOEXPAND * Don't expand the variables! | |
| *RTL_QUERY_REGISTRY_DIRECT * Results of query will be stored in EntryContext(QueryRoutine ignored) | |
| *RTL_QUERY_REGISTRY_DELETE * Delete value key after query | |
| ****************************** | |
| **Test layout(numbered according to CurrentTest value)** | |
| 0)NOVALUE Just make sure call-back works | |
| 1)Null Name See if QueryRoutine is called for every value in current key | |
| 2)SUBKEY See if we can use SUBKEY to change the current path on the fly | |
| 3)REQUIRED Test for value that's not there | |
| 4)NOEXPAND See if it will return multiple strings(no expand should split strings up) | |
| 5)DIRECT Make it store data directly in EntryContext and not call QueryRoutine | |
| 6)DefaultType Test return values when key isn't present | |
| 7)DefaultValue Test Default Value returned with key isn't present(and no REQUIRED flag set) | |
| 8)DefaultLength Test Default Length with DefaultType = REG_SZ | |
| 9)DefaultLength Test Default Length with DefaultType = REG_MULTI_SZ | |
| 10)DefaultLength Test Default Length with DefaultType = REG_EXPAND_SZ | |
| 11)DefaultData Test whether DefaultData is used while DefaultType = REG_NONE(shouldn't be) | |
| 12)Delete Try to delete value key | |
| */ | |
| NTSTATUS status; | |
| ULONG RelativeTo; | |
| PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL; | |
| RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/ | |
| QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26); | |
| pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26); | |
| QueryTable[0].QueryRoutine = QueryRoutine; | |
| QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOVALUE; | |
| QueryTable[0].Name = NULL; | |
| QueryTable[0].EntryContext = NULL; | |
| QueryTable[0].DefaultType = REG_BINARY; | |
| QueryTable[0].DefaultData = NULL; | |
| QueryTable[0].DefaultLength = 100; | |
| QueryTable[1].QueryRoutine = QueryRoutine; | |
| QueryTable[1].Flags = 0; | |
| QueryTable[1].Name = NULL; | |
| QueryTable[1].EntryContext = 0; | |
| QueryTable[1].DefaultType = REG_NONE; | |
| QueryTable[1].DefaultData = NULL; | |
| QueryTable[1].DefaultLength = 0; | |
| QueryTable[2].QueryRoutine = NULL; | |
| QueryTable[2].Flags = 0; | |
| QueryTable[2].Name = NULL; | |
| QueryTable[2].EntryContext = 0; | |
| QueryTable[2].DefaultType = REG_NONE; | |
| QueryTable[2].DefaultData = NULL; | |
| QueryTable[2].DefaultLength = 0; | |
| status = pRtlQueryRegistryValues(RelativeTo, winetestpath.Buffer, QueryTable, 0, 0); | |
| ok(status == STATUS_SUCCESS, "RtlQueryRegistryValues return: 0x%08x\n", status); | |
| pRtlFreeHeap(GetProcessHeap(), 0, QueryTable); | |
| } | |
| static void test_NtOpenKey(void) | |
| { | |
| HANDLE key; | |
| NTSTATUS status; | |
| OBJECT_ATTRIBUTES attr; | |
| ACCESS_MASK am = KEY_READ; | |
| UNICODE_STRING str; | |
| /* All NULL */ | |
| status = pNtOpenKey(NULL, 0, NULL); | |
| ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); | |
| /* NULL attributes */ | |
| status = pNtOpenKey(&key, 0, NULL); | |
| ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, | |
| "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| /* NULL key */ | |
| status = pNtOpenKey(NULL, am, &attr); | |
| ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); | |
| /* Length > sizeof(OBJECT_ATTRIBUTES) */ | |
| attr.Length *= 2; | |
| status = pNtOpenKey(&key, am, &attr); | |
| ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); | |
| /* Zero accessmask */ | |
| attr.Length = sizeof(attr); | |
| key = (HANDLE)0xdeadbeef; | |
| status = pNtOpenKey(&key, 0, &attr); | |
| todo_wine | |
| ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status); | |
| todo_wine | |
| ok(!key, "key = %p\n", key); | |
| if (status == STATUS_SUCCESS) NtClose(key); | |
| /* Calling without parent key requres full registry path. */ | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" ); | |
| InitializeObjectAttributes(&attr, &str, 0, 0, 0); | |
| key = (HANDLE)0xdeadbeef; | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status); | |
| todo_wine | |
| ok(!key, "key = %p\n", key); | |
| pRtlFreeUnicodeString( &str ); | |
| /* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */ | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey Failed: 0x%08x\n", status); | |
| attr.Attributes = OBJ_CASE_INSENSITIVE; | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| pNtClose(key); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" ); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| if (!pNtOpenKeyEx) | |
| { | |
| win_skip("NtOpenKeyEx not available\n"); | |
| return; | |
| } | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0); | |
| ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status); | |
| pNtClose(key); | |
| } | |
| static void test_NtCreateKey(void) | |
| { | |
| /*Create WineTest*/ | |
| OBJECT_ATTRIBUTES attr; | |
| HANDLE key, subkey; | |
| ACCESS_MASK am = GENERIC_ALL; | |
| NTSTATUS status; | |
| UNICODE_STRING str; | |
| /* All NULL */ | |
| status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0); | |
| ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, | |
| "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); | |
| /* Only the key */ | |
| status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0); | |
| ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, | |
| "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); | |
| /* Only accessmask */ | |
| status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0); | |
| ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, | |
| "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); | |
| /* Key and accessmask */ | |
| status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0); | |
| ok(status == STATUS_ACCESS_VIOLATION /* W2K3/XP/W2K */ || status == STATUS_INVALID_PARAMETER /* NT4 */, | |
| "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER(NT4), got: 0x%08x\n", status); | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| /* Only attributes */ | |
| status = pNtCreateKey(NULL, 0, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_ACCESS_DENIED /* Win7 */, | |
| "Expected STATUS_ACCESS_VIOLATION or STATUS_ACCESS_DENIED, got: 0x%08x\n", status); | |
| /* Length > sizeof(OBJECT_ATTRIBUTES) */ | |
| attr.Length *= 2; | |
| status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); | |
| attr.Length = sizeof(attr); | |
| status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08x\n", status); | |
| attr.RootDirectory = key; | |
| attr.ObjectName = &str; | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "test\\sub\\key" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "test\\subkey\\" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey\\" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS || broken(status == STATUS_OBJECT_NAME_NOT_FOUND), /* nt4 */ | |
| "NtCreateKey failed: 0x%08x\n", status ); | |
| if (status == STATUS_SUCCESS) | |
| { | |
| pNtDeleteKey( subkey ); | |
| pNtClose( subkey ); | |
| } | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "test_subkey" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pNtDeleteKey( subkey ); | |
| pNtClose( subkey ); | |
| attr.RootDirectory = 0; | |
| attr.Attributes = OBJ_CASE_INSENSITIVE; | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, | |
| "NtCreateKey failed: 0x%08x\n", status ); | |
| if (!status) pNtClose( subkey ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, | |
| "NtCreateKey failed: 0x%08x\n", status ); | |
| if (!status) pNtClose( subkey ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, | |
| "NtCreateKey failed: 0x%08x\n", status ); | |
| if (!status) pNtClose( subkey ); | |
| pRtlFreeUnicodeString( &str ); | |
| /* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */ | |
| attr.Attributes = 0; | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| todo_wine | |
| ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\Machine\\Software\\Classes" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, | |
| "NtCreateKey failed: 0x%08x\n", status ); | |
| if (!status) pNtClose( subkey ); | |
| pRtlFreeUnicodeString( &str ); | |
| pRtlCreateUnicodeStringFromAsciiz( &str, "\\REGISTRY\\MACHINE\\SOFTWARE\\CLASSES" ); | |
| status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, | |
| "NtCreateKey failed: 0x%08x\n", status ); | |
| if (!status) pNtClose( subkey ); | |
| pRtlFreeUnicodeString( &str ); | |
| pNtClose(key); | |
| } | |
| static void test_NtSetValueKey(void) | |
| { | |
| HANDLE key; | |
| NTSTATUS status; | |
| OBJECT_ATTRIBUTES attr; | |
| ACCESS_MASK am = KEY_WRITE; | |
| UNICODE_STRING ValName; | |
| DWORD data = 711; | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&key, am, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); | |
| status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data)); | |
| ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&ValName); | |
| pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest"); | |
| status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE); | |
| ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&ValName); | |
| pNtClose(key); | |
| } | |
| static void test_RtlOpenCurrentUser(void) | |
| { | |
| NTSTATUS status; | |
| HANDLE handle; | |
| status=pRtlOpenCurrentUser(KEY_READ, &handle); | |
| ok(status == STATUS_SUCCESS, "RtlOpenCurrentUser Failed: 0x%08x\n", status); | |
| pNtClose(handle); | |
| } | |
| static void test_RtlCheckRegistryKey(void) | |
| { | |
| NTSTATUS status; | |
| status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer); | |
| ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08x\n", status); | |
| status = pRtlCheckRegistryKey((RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL), winetestpath.Buffer); | |
| ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and RTL_REGISTRY_OPTIONAL: 0x%08x\n", status); | |
| } | |
| static void test_NtFlushKey(void) | |
| { | |
| NTSTATUS status; | |
| HANDLE hkey; | |
| OBJECT_ATTRIBUTES attr; | |
| ACCESS_MASK am = KEY_ALL_ACCESS; | |
| status = pNtFlushKey(NULL); | |
| ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| pNtOpenKey(&hkey, am, &attr); | |
| status = pNtFlushKey(hkey); | |
| ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status); | |
| pNtClose(hkey); | |
| } | |
| static void test_NtQueryValueKey(void) | |
| { | |
| HANDLE key; | |
| NTSTATUS status; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING ValName; | |
| KEY_VALUE_BASIC_INFORMATION *basic_info; | |
| KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi; | |
| KEY_VALUE_FULL_INFORMATION *full_info; | |
| DWORD len, expected; | |
| pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]); | |
| basic_info = HeapAlloc(GetProcessHeap(), 0, len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len); | |
| ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); | |
| ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex); | |
| ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type); | |
| ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength); | |
| ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len); | |
| basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); | |
| ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex); | |
| ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type); | |
| ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength); | |
| ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len); | |
| ok(!memcmp(basic_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n"); | |
| HeapFree(GetProcessHeap(), 0, basic_info); | |
| len = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]); | |
| partial_info = HeapAlloc(GetProcessHeap(), 0, len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); | |
| ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); | |
| ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex); | |
| ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); | |
| ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); | |
| ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len); | |
| partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); | |
| ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex); | |
| ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); | |
| ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); | |
| ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len); | |
| ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%x\n", *(DWORD *)partial_info->Data); | |
| HeapFree(GetProcessHeap(), 0, partial_info); | |
| len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]); | |
| full_info = HeapAlloc(GetProcessHeap(), 0, len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len); | |
| ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); | |
| ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex); | |
| ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type); | |
| ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength); | |
| ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength); | |
| ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength, | |
| "NtQueryValueKey returned wrong len %d\n", len); | |
| len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength; | |
| full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); | |
| ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex); | |
| ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type); | |
| ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength); | |
| ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength); | |
| ok(!memcmp(full_info->Name, ValName.Buffer, ValName.Length), "incorrect Name returned\n"); | |
| ok(*(DWORD *)((char *)full_info + full_info->DataOffset) == 711, "incorrect Data returned: 0x%x\n", | |
| *(DWORD *)((char *)full_info + full_info->DataOffset)); | |
| HeapFree(GetProcessHeap(), 0, full_info); | |
| pRtlFreeUnicodeString(&ValName); | |
| pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest"); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status); | |
| partial_info = HeapAlloc(GetProcessHeap(), 0, len+1); | |
| memset(partial_info, 0xbd, len+1); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); | |
| ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex); | |
| ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); | |
| ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); | |
| ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n"); | |
| ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE)); | |
| expected = len; | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 0, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status); | |
| ok(len == expected, "NtQueryValueKey wrong len %u\n", len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status); | |
| ok(len == expected, "NtQueryValueKey wrong len %u\n", len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) - 1, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08x\n", status); | |
| ok(len == expected, "NtQueryValueKey wrong len %u\n", len); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), &len); | |
| ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey wrong status 0x%08x\n", status); | |
| ok(len == expected, "NtQueryValueKey wrong len %u\n", len); | |
| HeapFree(GetProcessHeap(), 0, partial_info); | |
| pRtlFreeUnicodeString(&ValName); | |
| pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest"); | |
| status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0); | |
| ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); | |
| status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); | |
| ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type); | |
| ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength); | |
| pRtlFreeUnicodeString(&ValName); | |
| pNtClose(key); | |
| } | |
| static void test_NtDeleteKey(void) | |
| { | |
| NTSTATUS status; | |
| HANDLE hkey; | |
| OBJECT_ATTRIBUTES attr; | |
| ACCESS_MASK am = KEY_ALL_ACCESS; | |
| status = pNtDeleteKey(NULL); | |
| ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&hkey, am, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| status = pNtDeleteKey(hkey); | |
| ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status); | |
| } | |
| static void test_NtQueryLicenseKey(void) | |
| { | |
| static const WCHAR emptyW[] = {'E','M','P','T','Y',0}; | |
| UNICODE_STRING name; | |
| WORD buffer[32]; | |
| NTSTATUS status; | |
| ULONG type, len; | |
| DWORD value; | |
| if (!pNtQueryLicenseValue) | |
| { | |
| win_skip("NtQueryLicenseValue not found, skipping tests\n"); | |
| return; | |
| } | |
| type = 0xdead; | |
| len = 0xbeef; | |
| memset(&name, 0, sizeof(name)); | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| /* test with empty key */ | |
| pRtlCreateUnicodeStringFromAsciiz(&name, ""); | |
| type = 0xdead; | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| type = 0xdead; | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| type = 0xdead; | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| pRtlFreeUnicodeString(&name); | |
| /* test with nonexistent licence key */ | |
| pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value"); | |
| type = 0xdead; | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| type = 0xdead; | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| type = 0xdead; | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected succeeded\n"); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| pRtlFreeUnicodeString(&name); | |
| /* test with REG_SZ license key */ | |
| pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed"); | |
| type = 0xdead; | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| type = 0xdead; | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| type = 0xdead; | |
| len = 0; | |
| status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status); | |
| ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type); | |
| ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len); | |
| len = 0; | |
| status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status); | |
| ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len); | |
| type = 0xdead; | |
| len = 0; | |
| memset(buffer, 0x11, sizeof(buffer)); | |
| status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status); | |
| ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type); | |
| ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len); | |
| ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n"); | |
| type = 0xdead; | |
| len = 0; | |
| memset(buffer, 0x11, sizeof(buffer)); | |
| status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status); | |
| ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type); | |
| ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len); | |
| ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]); | |
| pRtlFreeUnicodeString(&name); | |
| /* test with REG_DWORD license key */ | |
| pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed"); | |
| type = 0xdead; | |
| len = 0xbeef; | |
| status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len); | |
| type = 0xdead; | |
| status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL); | |
| ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status); | |
| ok(type == 0xdead, "expected unmodified value for type, got %u\n", type); | |
| type = 0xdead; | |
| len = 0; | |
| status = pNtQueryLicenseValue(&name, &type, &value, 0, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status); | |
| ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type); | |
| ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len); | |
| len = 0; | |
| status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status); | |
| ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len); | |
| type = 0xdead; | |
| len = 0; | |
| value = 0xdeadbeef; | |
| status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status); | |
| ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type); | |
| ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len); | |
| ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n"); | |
| type = 0xdead; | |
| len = 0; | |
| status = pNtQueryLicenseValue(&name, &type, &value, 2, &len); | |
| ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status); | |
| ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type); | |
| ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len); | |
| pRtlFreeUnicodeString(&name); | |
| } | |
| static void test_RtlpNtQueryValueKey(void) | |
| { | |
| NTSTATUS status; | |
| status = pRtlpNtQueryValueKey(NULL, NULL, NULL, NULL, NULL); | |
| ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08x\n", status); | |
| } | |
| static void test_symlinks(void) | |
| { | |
| static const WCHAR linkW[] = {'l','i','n','k',0}; | |
| static const WCHAR valueW[] = {'v','a','l','u','e',0}; | |
| static const WCHAR symlinkW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0}; | |
| static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; | |
| static UNICODE_STRING null_str; | |
| char buffer[1024]; | |
| KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; | |
| WCHAR *target; | |
| UNICODE_STRING symlink_str, link_str, target_str, value_str; | |
| HANDLE root, key, link; | |
| OBJECT_ATTRIBUTES attr; | |
| NTSTATUS status; | |
| DWORD target_len, len, dw; | |
| pRtlInitUnicodeString( &link_str, linkW ); | |
| pRtlInitUnicodeString( &symlink_str, symlinkW ); | |
| pRtlInitUnicodeString( &target_str, targetW + 1 ); | |
| pRtlInitUnicodeString( &value_str, valueW ); | |
| target_len = winetestpath.Length + sizeof(targetW); | |
| target = pRtlAllocateHeap( GetProcessHeap(), 0, target_len + sizeof(targetW) /*for loop test*/ ); | |
| memcpy( target, winetestpath.Buffer, winetestpath.Length ); | |
| memcpy( target + winetestpath.Length/sizeof(WCHAR), targetW, sizeof(targetW) ); | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.Attributes = 0; | |
| attr.ObjectName = &winetestpath; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| status = pNtCreateKey( &root, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| attr.RootDirectory = root; | |
| attr.ObjectName = &link_str; | |
| status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| /* REG_SZ is not allowed */ | |
| status = pNtSetValueKey( link, &symlink_str, 0, REG_SZ, target, target_len ); | |
| ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status ); | |
| status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| /* other values are not allowed */ | |
| status = pNtSetValueKey( link, &link_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) ); | |
| ok( status == STATUS_ACCESS_DENIED, "NtSetValueKey wrong status 0x%08x\n", status ); | |
| /* try opening the target through the link */ | |
| attr.ObjectName = &link_str; | |
| key = (HANDLE)0xdeadbeef; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status ); | |
| ok( !key, "key = %p\n", key ); | |
| attr.ObjectName = &target_str; | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = 0xbeef; | |
| status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| attr.ObjectName = &link_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len ); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| /* REG_LINK can be created in non-link keys */ | |
| status = pNtSetValueKey( key, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| status = pNtDeleteValueKey( key, &symlink_str ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| attr.Attributes = 0; | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %u\n", len ); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| /* now open the symlink itself */ | |
| attr.RootDirectory = root; | |
| attr.Attributes = OBJ_OPENLINK; | |
| attr.ObjectName = &link_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| pNtClose( key ); | |
| if (pNtOpenKeyEx) | |
| { | |
| /* REG_OPTION_OPEN_LINK flag doesn't matter */ | |
| status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| pNtClose( key ); | |
| status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| pNtClose( key ); | |
| attr.Attributes = 0; | |
| status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| } | |
| attr.Attributes = OBJ_OPENLINK; | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| pNtClose( key ); | |
| /* delete target and create by NtCreateKey on link */ | |
| attr.ObjectName = &target_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| status = pNtDeleteKey( key ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| attr.ObjectName = &link_str; | |
| attr.Attributes = 0; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| if (status) /* can be removed once todo_wine above is fixed */ | |
| { | |
| attr.ObjectName = &target_str; | |
| attr.Attributes = OBJ_OPENLINK; | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| } | |
| attr.ObjectName = &target_str; | |
| attr.Attributes = OBJ_OPENLINK; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey wrong status 0x%08x\n", status ); | |
| if (0) /* crashes the Windows kernel on some Vista systems */ | |
| { | |
| /* reopen the link from itself */ | |
| attr.RootDirectory = link; | |
| attr.Attributes = OBJ_OPENLINK; | |
| attr.ObjectName = &null_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| pNtClose( key ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR), | |
| "wrong len %u\n", len ); | |
| pNtClose( key ); | |
| } | |
| if (0) /* crashes the Windows kernel in most versions */ | |
| { | |
| attr.RootDirectory = link; | |
| attr.Attributes = 0; | |
| attr.ObjectName = &null_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| } | |
| /* target with terminating null doesn't work */ | |
| status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| attr.RootDirectory = root; | |
| attr.Attributes = 0; | |
| attr.ObjectName = &link_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status ); | |
| /* relative symlink, works only on win2k */ | |
| status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, targetW+1, sizeof(targetW)-2*sizeof(WCHAR) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| attr.ObjectName = &link_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND, | |
| "NtOpenKey wrong status 0x%08x\n", status ); | |
| key = (HKEY)0xdeadbeef; | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, NULL ); | |
| ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status ); | |
| ok( !key, "key = %p\n", key ); | |
| status = pNtDeleteKey( link ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( link ); | |
| attr.ObjectName = &target_str; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| status = pNtDeleteKey( key ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| /* symlink loop */ | |
| status = pNtCreateKey( &link, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| memcpy( target + target_len/sizeof(WCHAR) - 1, targetW, sizeof(targetW) ); | |
| status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, | |
| target, target_len + sizeof(targetW) - sizeof(WCHAR) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NAME_TOO_LONG, | |
| "NtOpenKey failed: 0x%08x\n", status ); | |
| attr.Attributes = OBJ_OPENLINK; | |
| status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr ); | |
| ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status ); | |
| pNtClose( key ); | |
| status = pNtDeleteKey( link ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( link ); | |
| status = pNtDeleteKey( root ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( root ); | |
| pRtlFreeHeap(GetProcessHeap(), 0, target); | |
| } | |
| static WCHAR valueW[] = {'v','a','l','u','e'}; | |
| static UNICODE_STRING value_str = { sizeof(valueW), sizeof(valueW), valueW }; | |
| static const DWORD ptr_size = 8 * sizeof(void*); | |
| static DWORD get_key_value( HANDLE root, const char *name, DWORD flags ) | |
| { | |
| char tmp[32]; | |
| NTSTATUS status; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING str; | |
| HANDLE key; | |
| KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)tmp; | |
| DWORD dw, len = sizeof(tmp); | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = root; | |
| attr.Attributes = OBJ_CASE_INSENSITIVE; | |
| attr.ObjectName = &str; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| pRtlCreateUnicodeStringFromAsciiz( &str, name ); | |
| status = pNtCreateKey( &key, flags | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0; | |
| ok( status == STATUS_SUCCESS, "%08x: NtCreateKey failed: 0x%08x\n", flags, status ); | |
| status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| if (status == STATUS_OBJECT_NAME_NOT_FOUND) | |
| dw = 0; | |
| else | |
| { | |
| ok( status == STATUS_SUCCESS, "%08x: NtQueryValueKey failed: 0x%08x\n", flags, status ); | |
| dw = *(DWORD *)info->Data; | |
| } | |
| pNtClose( key ); | |
| pRtlFreeUnicodeString( &str ); | |
| return dw; | |
| } | |
| static void _check_key_value( int line, HANDLE root, const char *name, DWORD flags, DWORD expect ) | |
| { | |
| DWORD dw = get_key_value( root, name, flags ); | |
| ok_(__FILE__,line)( dw == expect, "%08x: wrong value %u/%u\n", flags, dw, expect ); | |
| } | |
| #define check_key_value(root,name,flags,expect) _check_key_value( __LINE__, root, name, flags, expect ) | |
| static void test_redirection(void) | |
| { | |
| static const WCHAR softwareW[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e',0}; | |
| static const WCHAR wownodeW[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','o','w','6','4','3','2','N','o','d','e',0}; | |
| static const WCHAR wine64W[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','i','n','e',0}; | |
| static const WCHAR wine32W[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','o','w','6','4','3','2','N','o','d','e','\\', | |
| 'W','i','n','e',0}; | |
| static const WCHAR key64W[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','i','n','e','\\','W','i','n','e','t','e','s','t',0}; | |
| static const WCHAR key32W[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'W','o','w','6','4','3','2','N','o','d','e','\\', | |
| 'W','i','n','e','\\', 'W','i','n','e','t','e','s','t',0}; | |
| static const WCHAR classes64W[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'C','l','a','s','s','e','s','\\', | |
| 'W','i','n','e',0}; | |
| static const WCHAR classes32W[] = {'\\','R','e','g','i','s','t','r','y','\\', | |
| 'M','a','c','h','i','n','e','\\', | |
| 'S','o','f','t','w','a','r','e','\\', | |
| 'C','l','a','s','s','e','s','\\', | |
| 'W','o','w','6','4','3','2','N','o','d','e','\\', | |
| 'W','i','n','e',0}; | |
| NTSTATUS status; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING str; | |
| char buffer[1024]; | |
| KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; | |
| DWORD dw, len; | |
| HANDLE key, root32, root64, key32, key64; | |
| BOOL is_vista = FALSE; | |
| if (ptr_size != 64) | |
| { | |
| ULONG is_wow64, len; | |
| if (pNtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, | |
| &is_wow64, sizeof(is_wow64), &len ) || | |
| !is_wow64) | |
| { | |
| trace( "Not on Wow64, no redirection\n" ); | |
| return; | |
| } | |
| } | |
| attr.Length = sizeof(attr); | |
| attr.RootDirectory = 0; | |
| attr.Attributes = OBJ_CASE_INSENSITIVE; | |
| attr.ObjectName = &str; | |
| attr.SecurityDescriptor = NULL; | |
| attr.SecurityQualityOfService = NULL; | |
| pRtlInitUnicodeString( &str, wine64W ); | |
| status = pNtCreateKey( &root64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlInitUnicodeString( &str, wine32W ); | |
| status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlInitUnicodeString( &str, key64W ); | |
| status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlInitUnicodeString( &str, key32W ); | |
| status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = 64; | |
| status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| dw = 32; | |
| status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| dw = *(DWORD *)info->Data; | |
| ok( dw == 32, "wrong value %u\n", dw ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| dw = *(DWORD *)info->Data; | |
| ok( dw == 64, "wrong value %u\n", dw ); | |
| pRtlInitUnicodeString( &str, softwareW ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| if (ptr_size == 32) | |
| { | |
| /* the Vista mechanism allows opening Wow6432Node from a 32-bit key too */ | |
| /* the new (and simpler) Win7 mechanism doesn't */ | |
| if (get_key_value( key, "Wow6432Node\\Wine\\Winetest", 0 ) == 32) | |
| { | |
| trace( "using Vista-style Wow6432Node handling\n" ); | |
| is_vista = TRUE; | |
| } | |
| check_key_value( key, "Wine\\Winetest", 0, 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 ); | |
| } | |
| else | |
| { | |
| check_key_value( key, "Wine\\Winetest", 0, 64 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 ); | |
| } | |
| pNtClose( key ); | |
| if (ptr_size == 32) | |
| { | |
| status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = get_key_value( key, "Wine\\Winetest", 0 ); | |
| ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, 64 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, 32 ); | |
| dw = get_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY ); | |
| ok( dw == 32 || broken(dw == 64) /* xp64 */, "wrong value %u\n", dw ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Wine\\Winetest", 0, 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", 0, is_vista ? 32 : 0 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 0 ); | |
| check_key_value( key, "Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, is_vista ? 32 : 0 ); | |
| pNtClose( key ); | |
| } | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", 0, ptr_size ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", 0, 32 ); | |
| if (ptr_size == 64) | |
| { | |
| /* KEY_WOW64 flags have no effect on 64-bit */ | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 64 ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, 32 ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| } | |
| else | |
| { | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_64KEY, 64 ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( 0, "\\Registry\\Machine\\Software\\Wow6432Node\\Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| } | |
| pRtlInitUnicodeString( &str, wownodeW ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Wine\\Winetest", 0, 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, (ptr_size == 64) ? 32 : (is_vista ? 64 : 32) ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| if (ptr_size == 32) | |
| { | |
| status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = get_key_value( key, "Wine\\Winetest", 0 ); | |
| ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Wine\\Winetest", 0, 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Wine\\Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| } | |
| pRtlInitUnicodeString( &str, wine32W ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Winetest", 0, 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_64KEY, (ptr_size == 32 && is_vista) ? 64 : 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| if (ptr_size == 32) | |
| { | |
| status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = get_key_value( key, "Winetest", 0 ); | |
| ok( dw == 32 || (is_vista && dw == 64), "wrong value %u\n", dw ); | |
| check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Winetest", 0, 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| } | |
| pRtlInitUnicodeString( &str, wine64W ); | |
| status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Winetest", 0, ptr_size ); | |
| check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : ptr_size ); | |
| check_key_value( key, "Winetest", KEY_WOW64_32KEY, ptr_size ); | |
| pNtClose( key ); | |
| if (ptr_size == 32) | |
| { | |
| status = pNtCreateKey( &key, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = get_key_value( key, "Winetest", 0 ); | |
| ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %u\n", dw ); | |
| check_key_value( key, "Winetest", KEY_WOW64_64KEY, 64 ); | |
| dw = get_key_value( key, "Winetest", KEY_WOW64_32KEY ); | |
| todo_wine ok( dw == 32, "wrong value %u\n", dw ); | |
| pNtClose( key ); | |
| status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| check_key_value( key, "Winetest", 0, 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_64KEY, is_vista ? 64 : 32 ); | |
| check_key_value( key, "Winetest", KEY_WOW64_32KEY, 32 ); | |
| pNtClose( key ); | |
| } | |
| status = pNtDeleteKey( key32 ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( key32 ); | |
| status = pNtDeleteKey( key64 ); | |
| ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status ); | |
| pNtClose( key64 ); | |
| pNtDeleteKey( root32 ); | |
| pNtClose( root32 ); | |
| pNtDeleteKey( root64 ); | |
| pNtClose( root64 ); | |
| /* Software\Classes is shared/reflected so behavior is different */ | |
| pRtlInitUnicodeString( &str, classes64W ); | |
| status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| if (status == STATUS_ACCESS_DENIED) | |
| { | |
| skip("Not authorized to modify the Classes key\n"); | |
| return; | |
| } | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| pRtlInitUnicodeString( &str, classes32W ); | |
| status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| dw = 64; | |
| status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key64 ); | |
| dw = 32; | |
| status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| pNtClose( key32 ); | |
| pRtlInitUnicodeString( &str, classes64W ); | |
| status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| dw = *(DWORD *)info->Data; | |
| ok( dw == ptr_size, "wrong value %u\n", dw ); | |
| pRtlInitUnicodeString( &str, classes32W ); | |
| status = pNtCreateKey( &key32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); | |
| ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); | |
| len = sizeof(buffer); | |
| status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len ); | |
| ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status ); | |
| dw = *(DWORD *)info->Data; | |
| ok( dw == 32, "wrong value %u\n", dw ); | |
| pNtDeleteKey( key32 ); | |
| pNtClose( key32 ); | |
| pNtDeleteKey( key64 ); | |
| pNtClose( key64 ); | |
| } | |
| static void test_long_value_name(void) | |
| { | |
| HANDLE key; | |
| NTSTATUS status, expected; | |
| OBJECT_ATTRIBUTES attr; | |
| UNICODE_STRING ValName; | |
| DWORD i; | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&key, KEY_WRITE|KEY_READ, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| ValName.MaximumLength = 0xfffc; | |
| ValName.Length = ValName.MaximumLength - sizeof(WCHAR); | |
| ValName.Buffer = HeapAlloc(GetProcessHeap(), 0, ValName.MaximumLength); | |
| for (i = 0; i < ValName.Length / sizeof(WCHAR); i++) | |
| ValName.Buffer[i] = 'a'; | |
| ValName.Buffer[i] = 0; | |
| status = pNtDeleteValueKey(key, &ValName); | |
| ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtDeleteValueKey with nonexistent long value name returned 0x%08x\n", status); | |
| status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &i, sizeof(i)); | |
| ok(status == STATUS_INVALID_PARAMETER || broken(status == STATUS_SUCCESS) /* nt4 */, | |
| "NtSetValueKey with long value name returned 0x%08x\n", status); | |
| expected = (status == STATUS_SUCCESS) ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND; | |
| status = pNtDeleteValueKey(key, &ValName); | |
| ok(status == expected, "NtDeleteValueKey with long value name returned 0x%08x\n", status); | |
| status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, NULL, 0, &i); | |
| ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey with nonexistent long value name returned 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&ValName); | |
| pNtClose(key); | |
| } | |
| static void test_NtQueryKey(void) | |
| { | |
| HANDLE key, subkey, subkey2; | |
| NTSTATUS status; | |
| OBJECT_ATTRIBUTES attr; | |
| ULONG length, len; | |
| KEY_NAME_INFORMATION *info = NULL; | |
| KEY_CACHED_INFORMATION cached_info; | |
| UNICODE_STRING str; | |
| DWORD dw; | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&key, KEY_READ, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length); | |
| if (status == STATUS_INVALID_PARAMETER) { | |
| win_skip("KeyNameInformation is not supported\n"); | |
| pNtClose(key); | |
| return; | |
| } | |
| todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status); | |
| info = HeapAlloc(GetProcessHeap(), 0, length); | |
| /* non-zero buffer size, but insufficient */ | |
| status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len); | |
| ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status); | |
| ok(length == len, "got %d, expected %d\n", len, length); | |
| ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n", | |
| info->NameLength, winetestpath.Length); | |
| /* correct buffer size */ | |
| status = pNtQueryKey(key, KeyNameInformation, info, length, &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); | |
| ok(length == len, "got %d, expected %d\n", len, length); | |
| str.Buffer = info->Name; | |
| str.Length = info->NameLength; | |
| ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0, | |
| "got %s, expected %s\n", | |
| wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)), | |
| wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR))); | |
| HeapFree(GetProcessHeap(), 0, info); | |
| attr.RootDirectory = key; | |
| attr.ObjectName = &str; | |
| pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); | |
| status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&str); | |
| status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); | |
| if (status == STATUS_SUCCESS) | |
| { | |
| ok(len == sizeof(cached_info), "got unexpected length %d\n", len); | |
| ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys); | |
| ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen); | |
| ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values); | |
| ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen); | |
| ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen); | |
| ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength); | |
| } | |
| attr.RootDirectory = subkey; | |
| attr.ObjectName = &str; | |
| pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2"); | |
| status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&str); | |
| pRtlCreateUnicodeStringFromAsciiz(&str, "val"); | |
| dw = 64; | |
| status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) ); | |
| ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); | |
| pRtlFreeUnicodeString(&str); | |
| status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len); | |
| ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); | |
| if (status == STATUS_SUCCESS) | |
| { | |
| ok(len == sizeof(cached_info), "got unexpected length %d\n", len); | |
| ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys); | |
| ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen); | |
| ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values); | |
| ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen); | |
| ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen); | |
| ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength); | |
| } | |
| status = pNtDeleteKey(subkey2); | |
| ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); | |
| status = pNtDeleteKey(subkey); | |
| ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); | |
| pNtClose(subkey2); | |
| pNtClose(subkey); | |
| pNtClose(key); | |
| } | |
| static void test_notify(void) | |
| { | |
| OBJECT_ATTRIBUTES attr; | |
| LARGE_INTEGER timeout; | |
| IO_STATUS_BLOCK iosb; | |
| UNICODE_STRING str; | |
| HANDLE key, events[2], subkey; | |
| NTSTATUS status; | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| events[0] = CreateEventW(NULL, FALSE, TRUE, NULL); | |
| ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError()); | |
| events[1] = CreateEventW(NULL, FALSE, TRUE, NULL); | |
| ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError()); | |
| status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| timeout.QuadPart = 0; | |
| status = pNtWaitForSingleObject(events[0], FALSE, &timeout); | |
| ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status); | |
| status = pNtWaitForSingleObject(events[1], FALSE, &timeout); | |
| ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status); | |
| attr.RootDirectory = key; | |
| attr.ObjectName = &str; | |
| pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); | |
| status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&str); | |
| status = pNtWaitForSingleObject(events[0], FALSE, &timeout); | |
| todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| status = pNtWaitForSingleObject(events[1], FALSE, &timeout); | |
| ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| status = pNtDeleteKey(subkey); | |
| ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); | |
| status = pNtWaitForSingleObject(events[0], FALSE, &timeout); | |
| todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| status = pNtWaitForSingleObject(events[1], FALSE, &timeout); | |
| ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| pNtClose(subkey); | |
| status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| pNtClose(key); | |
| status = pNtWaitForSingleObject(events[0], FALSE, &timeout); | |
| todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| status = pNtWaitForSingleObject(events[1], FALSE, &timeout); | |
| ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| if (pNtNotifyChangeMultipleKeys) | |
| { | |
| InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); | |
| status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr); | |
| ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); | |
| status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE); | |
| ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); | |
| timeout.QuadPart = 0; | |
| status = pNtWaitForSingleObject(events[0], FALSE, &timeout); | |
| ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status); | |
| attr.RootDirectory = key; | |
| attr.ObjectName = &str; | |
| pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); | |
| status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); | |
| ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); | |
| pRtlFreeUnicodeString(&str); | |
| status = pNtWaitForSingleObject(events[0], FALSE, &timeout); | |
| ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); | |
| status = pNtDeleteKey(subkey); | |
| ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); | |
| pNtClose(subkey); | |
| pNtClose(key); | |
| } | |
| else | |
| { | |
| win_skip("NtNotifyChangeMultipleKeys not available\n"); | |
| } | |
| pNtClose(events[0]); | |
| pNtClose(events[1]); | |
| } | |
| START_TEST(reg) | |
| { | |
| static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0}; | |
| if(!InitFunctionPtrs()) | |
| return; | |
| pRtlFormatCurrentUserKeyPath(&winetestpath); | |
| winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer, | |
| winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR)); | |
| winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR); | |
| pRtlAppendUnicodeToString(&winetestpath, winetest); | |
| test_NtCreateKey(); | |
| test_NtOpenKey(); | |
| test_NtSetValueKey(); | |
| test_RtlCheckRegistryKey(); | |
| test_RtlOpenCurrentUser(); | |
| test_RtlQueryRegistryValues(); | |
| test_RtlpNtQueryValueKey(); | |
| test_NtFlushKey(); | |
| test_NtQueryKey(); | |
| test_NtQueryLicenseKey(); | |
| test_NtQueryValueKey(); | |
| test_long_value_name(); | |
| test_notify(); | |
| test_NtDeleteKey(); | |
| test_symlinks(); | |
| test_redirection(); | |
| pRtlFreeUnicodeString(&winetestpath); | |
| FreeLibrary(hntdll); | |
| } |