2133 lines
98 KiB
C
2133 lines
98 KiB
C
/* 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 * pNtEnumerateKey)(HANDLE, ULONG, KEY_INFORMATION_CLASS, void *, DWORD, DWORD *);
|
|
static NTSTATUS (WINAPI * pNtEnumerateValueKey)(HANDLE, ULONG, KEY_VALUE_INFORMATION_CLASS, void *, DWORD, DWORD *);
|
|
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 * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, void *, 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 * pRtlCreateRegistryKey)(ULONG, PWSTR);
|
|
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(NtEnumerateKey)
|
|
NTDLL_GET_PROC(NtEnumerateValueKey)
|
|
NTDLL_GET_PROC(NtFlushKey)
|
|
NTDLL_GET_PROC(NtDeleteKey)
|
|
NTDLL_GET_PROC(NtQueryKey)
|
|
NTDLL_GET_PROC(NtQueryObject)
|
|
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(RtlCreateRegistryKey)
|
|
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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\n", status);
|
|
todo_wine
|
|
ok(!key, "key = %p\n", key);
|
|
if (status == STATUS_SUCCESS) NtClose(key);
|
|
|
|
/* Calling without parent key requires 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%08lx\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);
|
|
ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_SUCCESS /* Win10 1607+ */,
|
|
"NtOpenKey Failed: 0x%08lx\n", status);
|
|
if (!status) pNtClose( key );
|
|
|
|
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
status = pNtOpenKey(&key, KEY_READ, &attr);
|
|
ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\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%08lx\n", status );
|
|
pRtlFreeUnicodeString( &str );
|
|
|
|
pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
|
|
status = pNtOpenKey(&key, KEY_READ, &attr);
|
|
todo_wine
|
|
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08lx\n", status );
|
|
pRtlFreeUnicodeString( &str );
|
|
|
|
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
|
|
status = pNtOpenKey(&key, KEY_READ, &attr);
|
|
todo_wine
|
|
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
|
pNtClose( key );
|
|
pRtlFreeUnicodeString( &str );
|
|
|
|
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\" );
|
|
status = pNtOpenKey(&key, KEY_READ, &attr);
|
|
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\n", status);
|
|
|
|
attr.Length = sizeof(attr);
|
|
status = pNtCreateKey(&key, am, &attr, 0, 0, 0, 0);
|
|
ok(status == STATUS_SUCCESS, "NtCreateKey Failed: 0x%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\n", status );
|
|
if (!status) pNtClose( subkey );
|
|
pRtlFreeUnicodeString( &str );
|
|
|
|
/* the REGISTRY part is case-sensitive unless OBJ_CASE_INSENSITIVE is specified */
|
|
am = GENERIC_READ;
|
|
attr.Attributes = 0;
|
|
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\Machine\\Software\\Classes" );
|
|
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
|
|
ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_SUCCESS /* Win10 1607+ */,
|
|
"NtCreateKey failed: 0x%08lx\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,
|
|
"NtCreateKey failed: 0x%08lx\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,
|
|
"NtCreateKey failed: 0x%08lx\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%08lx\n", status);
|
|
|
|
pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest");
|
|
status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data));
|
|
ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08lx\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%08lx\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%08lx\n", status);
|
|
pNtClose(handle);
|
|
}
|
|
|
|
static void test_RtlCheckRegistryKey(void)
|
|
{
|
|
static WCHAR empty[] = {0};
|
|
NTSTATUS status;
|
|
|
|
status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
|
|
ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE: 0x%08lx\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%08lx\n", status);
|
|
|
|
status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, NULL);
|
|
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and Path being NULL: 0x%08lx\n", status);
|
|
|
|
status = pRtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, empty);
|
|
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCheckRegistryKey with RTL_REGISTRY_ABSOLUTE and Path being empty: 0x%08lx\n", status);
|
|
|
|
status = pRtlCheckRegistryKey(RTL_REGISTRY_USER, NULL);
|
|
ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_USER and Path being NULL: 0x%08lx\n", status);
|
|
|
|
status = pRtlCheckRegistryKey(RTL_REGISTRY_USER, empty);
|
|
ok(status == STATUS_SUCCESS, "RtlCheckRegistryKey with RTL_REGISTRY_USER and Path being empty: 0x%08lx\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%08lx\n", status);
|
|
|
|
InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
|
|
pNtOpenKey(&hkey, am, &attr);
|
|
|
|
status = pNtFlushKey(hkey);
|
|
ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\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%08lx\n", status);
|
|
|
|
len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
|
|
basic_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*basic_info));
|
|
status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len);
|
|
ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08lx\n", status);
|
|
ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", basic_info->TitleIndex);
|
|
ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %ld\n", basic_info->Type);
|
|
ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %ld\n", basic_info->NameLength);
|
|
ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %ld\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%08lx\n", status);
|
|
ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", basic_info->TitleIndex);
|
|
ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %ld\n", basic_info->Type);
|
|
ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %ld\n", basic_info->NameLength);
|
|
ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %ld\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, sizeof(*partial_info));
|
|
status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len);
|
|
ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08lx\n", status);
|
|
ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", partial_info->TitleIndex);
|
|
ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %ld\n", partial_info->Type);
|
|
ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %ld\n", partial_info->DataLength);
|
|
ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %ld\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%08lx\n", status);
|
|
ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", partial_info->TitleIndex);
|
|
ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %ld\n", partial_info->Type);
|
|
ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %ld\n", partial_info->DataLength);
|
|
ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %ld\n", len);
|
|
ok(*(DWORD *)partial_info->Data == 711, "incorrect Data returned: 0x%lx\n", *(DWORD *)partial_info->Data);
|
|
HeapFree(GetProcessHeap(), 0, partial_info);
|
|
|
|
len = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
|
|
full_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*full_info));
|
|
status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len);
|
|
ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08lx\n", status);
|
|
ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", full_info->TitleIndex);
|
|
ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %ld\n", full_info->Type);
|
|
ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %ld\n", full_info->DataLength);
|
|
ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %ld\n", full_info->NameLength);
|
|
ok(len == FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + full_info->DataLength + full_info->NameLength,
|
|
"NtQueryValueKey returned wrong len %ld\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%08lx\n", status);
|
|
ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", full_info->TitleIndex);
|
|
ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %ld\n", full_info->Type);
|
|
ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %ld\n", full_info->DataLength);
|
|
ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %ld\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%lx\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%08lx\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%08lx\n", status);
|
|
ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %ld\n", partial_info->TitleIndex);
|
|
ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %ld\n", partial_info->Type);
|
|
ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %ld\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%08lx\n", status);
|
|
ok(len == expected, "NtQueryValueKey wrong len %lu\n", len);
|
|
status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, 1, &len);
|
|
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey wrong status 0x%08lx\n", status);
|
|
ok(len == expected, "NtQueryValueKey wrong len %lu\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%08lx\n", status);
|
|
ok(len == expected, "NtQueryValueKey wrong len %lu\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%08lx\n", status);
|
|
ok(len == expected, "NtQueryValueKey wrong len %lu\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%08lx\n", status);
|
|
|
|
status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len);
|
|
ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08lx\n", status);
|
|
ok(pi.Type == 0xff00ff00, "Type=%lx\n", pi.Type);
|
|
ok(pi.DataLength == 0, "DataLength=%lu\n", pi.DataLength);
|
|
pRtlFreeUnicodeString(&ValName);
|
|
|
|
pNtClose(key);
|
|
}
|
|
|
|
static void test_NtDeleteKey(void)
|
|
{
|
|
UNICODE_STRING string;
|
|
char buffer[200];
|
|
NTSTATUS status;
|
|
HANDLE hkey, hkey2;
|
|
OBJECT_ATTRIBUTES attr;
|
|
DWORD size;
|
|
|
|
status = pNtDeleteKey(NULL);
|
|
ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got: 0x%08lx\n", status);
|
|
|
|
InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
|
|
status = pNtOpenKey(&hkey, KEY_ALL_ACCESS, &attr);
|
|
ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
|
|
|
|
status = pNtDeleteKey(hkey);
|
|
ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08lx\n", status);
|
|
|
|
status = pNtQueryKey(hkey, KeyNameInformation, buffer, sizeof(buffer), &size);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtEnumerateKey(hkey, 0, KeyFullInformation, buffer, sizeof(buffer), &size);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
pRtlInitUnicodeString(&string, L"value");
|
|
status = pNtQueryValueKey(hkey, &string, KeyValueBasicInformation, buffer, sizeof(buffer), &size);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtEnumerateValueKey(hkey, 0, KeyValuePartialInformation, buffer, sizeof(buffer), &size);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtSetValueKey(hkey, &string, 0, REG_SZ, "test", 5);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtDeleteValueKey(hkey, &string);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtDeleteKey(hkey);
|
|
todo_wine ok(!status, "got %#lx\n", status);
|
|
|
|
RtlInitUnicodeString(&string, L"subkey");
|
|
InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE, hkey, NULL);
|
|
status = pNtOpenKey(&hkey2, KEY_READ, &attr);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtCreateKey(&hkey2, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtQueryObject(hkey, ObjectNameInformation, buffer, sizeof(buffer), &size);
|
|
ok(status == STATUS_KEY_DELETED, "got %#lx\n", status);
|
|
|
|
status = pNtQueryObject(hkey, ObjectBasicInformation, buffer, sizeof(OBJECT_BASIC_INFORMATION), &size);
|
|
ok(!status, "got %#lx\n", status);
|
|
|
|
status = pNtClose(hkey);
|
|
ok(status == STATUS_SUCCESS, "got %#lx\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 %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\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 %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\n", len);
|
|
|
|
type = 0xdead;
|
|
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
|
|
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
|
|
len = 0xbeef;
|
|
status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
|
|
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\n", len);
|
|
|
|
type = 0xdead;
|
|
len = 0xbeef;
|
|
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
|
|
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\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 %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\n", len);
|
|
|
|
type = 0xdead;
|
|
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
|
|
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
|
|
len = 0xbeef;
|
|
status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
|
|
ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08lx, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
|
|
ok(len == 0xbeef || broken(!len) /* Win10 1607 */, "expected unmodified value for len, got %lu\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 %lu\n", type);
|
|
ok(len == 0xbeef || broken(!len) /* Win10 1607 */, "expected unmodified value for len, got %lu\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 %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\n", len);
|
|
|
|
type = 0xdead;
|
|
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
|
|
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
|
|
type = 0xdead;
|
|
len = 0;
|
|
status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
|
|
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08lx, expected STATUS_BUFFER_TOO_SMALL\n", status);
|
|
ok(type == REG_SZ, "expected type = REG_SZ, got %lu\n", type);
|
|
ok(len == sizeof(emptyW), "expected len = %lu, got %lu\n", (DWORD)sizeof(emptyW), len);
|
|
|
|
len = 0;
|
|
status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
|
|
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08lx, expected STATUS_BUFFER_TOO_SMALL\n", status);
|
|
ok(len == sizeof(emptyW), "expected len = %lu, got %lu\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 %08lx, expected STATUS_SUCCESS\n", status);
|
|
ok(type == REG_SZ, "expected type = REG_SZ, got %lu\n", type);
|
|
ok(len == sizeof(emptyW), "expected len = %lu, got %lu\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 %08lx, expected STATUS_BUFFER_TOO_SMALL\n", status);
|
|
ok(type == REG_SZ, "expected type REG_SZ, got %lu\n", type);
|
|
ok(len == sizeof(emptyW), "expected len = %lu, got %lu\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 %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
ok(len == 0xbeef, "expected unmodified value for len, got %lu\n", len);
|
|
|
|
type = 0xdead;
|
|
status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
|
|
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08lx, expected STATUS_INVALID_PARAMETER\n", status);
|
|
ok(type == 0xdead, "expected unmodified value for type, got %lu\n", type);
|
|
|
|
type = 0xdead;
|
|
len = 0;
|
|
status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
|
|
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08lx, expected STATUS_BUFFER_TOO_SMALL\n", status);
|
|
ok(type == REG_DWORD, "expected type = REG_DWORD, got %lu\n", type);
|
|
ok(len == sizeof(value), "expected len = %lu, got %lu\n", (DWORD)sizeof(value), len);
|
|
|
|
len = 0;
|
|
status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
|
|
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08lx, expected STATUS_BUFFER_TOO_SMALL\n", status);
|
|
ok(len == sizeof(value), "expected len = %lu, got %lu\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 %08lx, expected STATUS_SUCCESS\n", status);
|
|
ok(type == REG_DWORD, "expected type = REG_DWORD, got %lu\n", type);
|
|
ok(len == sizeof(value), "expected len = %lu, got %lu\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 %08lx, expected STATUS_BUFFER_TOO_SMALL\n", status);
|
|
ok(type == REG_DWORD, "expected type REG_DWORD, got %lu\n", type);
|
|
ok(len == sizeof(value), "expected len = %lu, got %lu\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%08lx\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%08lx\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%08lx\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%08lx\n", status );
|
|
status = pNtSetValueKey( link, &symlink_str, 0, REG_LINK, target, target_len - sizeof(WCHAR) );
|
|
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\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%08lx\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%08lx\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%08lx\n", status );
|
|
|
|
dw = 0xbeef;
|
|
status = pNtSetValueKey( key, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
|
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\n", status );
|
|
pNtClose( key );
|
|
|
|
attr.ObjectName = &link_str;
|
|
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
|
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %lu\n", len );
|
|
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08lx\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%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\n", len );
|
|
status = pNtDeleteValueKey( key, &symlink_str );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteValueKey failed: 0x%08lx\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%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &value_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + sizeof(DWORD), "wrong len %lu\n", len );
|
|
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08lx\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%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\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%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\n", len );
|
|
pNtClose( key );
|
|
|
|
status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 );
|
|
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\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%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08lx\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%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\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%08lx\n", status );
|
|
status = pNtDeleteKey( key );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08lx\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%08lx\n", status );
|
|
|
|
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
|
todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\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%08lx\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%08lx\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%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\n", len );
|
|
pNtClose( key );
|
|
|
|
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
|
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
|
"wrong len %lu\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%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
pNtClose( key );
|
|
|
|
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
|
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08lx\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%08lx\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%08lx\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%08lx\n", status );
|
|
attr.ObjectName = &link_str;
|
|
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_NAME_INVALID /* Win10 1607+ */,
|
|
"NtOpenKey wrong status 0x%08lx\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%08lx\n", status );
|
|
ok( !key, "key = %p\n", key );
|
|
|
|
status = pNtDeleteKey( link );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08lx\n", status );
|
|
pNtClose( link );
|
|
|
|
attr.ObjectName = &target_str;
|
|
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
|
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
|
status = pNtDeleteKey( key );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08lx\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%08lx\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%08lx\n", status );
|
|
|
|
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
|
ok( status == STATUS_OBJECT_NAME_NOT_FOUND /* XP */
|
|
|| status == STATUS_NAME_TOO_LONG
|
|
|| status == STATUS_INVALID_PARAMETER /* Win10 1607+ */,
|
|
"NtOpenKey failed: 0x%08lx\n", status );
|
|
|
|
attr.Attributes = OBJ_OPENLINK;
|
|
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
|
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
|
|
pNtClose( key );
|
|
|
|
status = pNtDeleteKey( link );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08lx\n", status );
|
|
pNtClose( link );
|
|
|
|
status = pNtDeleteKey( root );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08lx\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, "%08lx: NtCreateKey failed: 0x%08lx\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, "%08lx: NtQueryValueKey failed: 0x%08lx\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, "%08lx: wrong value %lu/%lu\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 );
|
|
if (status == STATUS_ACCESS_DENIED)
|
|
{
|
|
skip("Not authorized to modify KEY_WOW64_64KEY, no redirection\n");
|
|
return;
|
|
}
|
|
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\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%08lx\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%08lx\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%08lx\n", status );
|
|
|
|
dw = 64;
|
|
status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
|
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\n", status );
|
|
|
|
dw = 32;
|
|
status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
|
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\n", status );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
dw = *(DWORD *)info->Data;
|
|
ok( dw == 32, "wrong value %lu\n", dw );
|
|
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
dw = *(DWORD *)info->Data;
|
|
ok( dw == 64, "wrong value %lu\n", dw );
|
|
|
|
pRtlInitUnicodeString( &str, softwareW );
|
|
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
|
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\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%08lx\n", status );
|
|
dw = get_key_value( key, "Wine\\Winetest", 0 );
|
|
ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %lu\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 %lu\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%08lx\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%08lx\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%08lx\n", status );
|
|
dw = get_key_value( key, "Wine\\Winetest", 0 );
|
|
ok( dw == (is_vista ? 64 : 32) || broken(dw == 32) /* xp64 */, "wrong value %lu\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%08lx\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%08lx\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%08lx\n", status );
|
|
dw = get_key_value( key, "Winetest", 0 );
|
|
ok( dw == 32 || (is_vista && dw == 64), "wrong value %lu\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%08lx\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%08lx\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%08lx\n", status );
|
|
dw = get_key_value( key, "Winetest", 0 );
|
|
ok( dw == 64 || broken(dw == 32) /* xp64 */, "wrong value %lu\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 %lu\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%08lx\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%08lx\n", status );
|
|
pNtClose( key32 );
|
|
|
|
status = pNtDeleteKey( key64 );
|
|
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08lx\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%08lx\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%08lx\n", status );
|
|
|
|
dw = 64;
|
|
status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
|
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\n", status );
|
|
pNtClose( key64 );
|
|
|
|
dw = 32;
|
|
status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
|
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\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%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key64, &value_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
dw = *(DWORD *)info->Data;
|
|
ok( dw == ptr_size, "wrong value %lu\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%08lx\n", status );
|
|
len = sizeof(buffer);
|
|
status = pNtQueryValueKey( key32, &value_str, KeyValuePartialInformation, info, len, &len );
|
|
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08lx\n", status );
|
|
dw = *(DWORD *)info->Data;
|
|
ok( dw == 32, "wrong value %lu\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\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%08lx\n", status);
|
|
ok(length == len, "got %ld, expected %ld\n", len, length);
|
|
ok(info->NameLength == winetestpath.Length, "got %ld, expected %d\n",
|
|
info->NameLength, winetestpath.Length);
|
|
|
|
/* correct buffer size */
|
|
status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
|
|
ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status);
|
|
ok(length == len, "got %ld, expected %ld\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%08lx\n", status);
|
|
pRtlFreeUnicodeString(&str);
|
|
|
|
status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
|
|
ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
ok(len == sizeof(cached_info), "got unexpected length %ld\n", len);
|
|
ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %lu\n", cached_info.SubKeys);
|
|
ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %lu\n", cached_info.MaxNameLen);
|
|
ok(cached_info.Values == 0, "cached_info.Values = %lu\n", cached_info.Values);
|
|
ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %lu\n", cached_info.MaxValueNameLen);
|
|
ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %lu\n", cached_info.MaxValueDataLen);
|
|
ok(cached_info.NameLength == 22, "cached_info.NameLength = %lu\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%08lx\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%08lx\n", status );
|
|
pRtlFreeUnicodeString(&str);
|
|
|
|
status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
|
|
ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08lx\n", status);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
ok(len == sizeof(cached_info), "got unexpected length %ld\n", len);
|
|
ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %lu\n", cached_info.SubKeys);
|
|
ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %lu\n", cached_info.MaxNameLen);
|
|
ok(cached_info.Values == 1, "cached_info.Values = %lu\n", cached_info.Values);
|
|
ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %lu\n", cached_info.MaxValueNameLen);
|
|
ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %lu\n", cached_info.MaxValueDataLen);
|
|
ok(cached_info.NameLength == 22, "cached_info.NameLength = %lu\n", cached_info.NameLength);
|
|
}
|
|
|
|
status = pNtDeleteKey(subkey2);
|
|
ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %lx\n", status);
|
|
status = pNtDeleteKey(subkey);
|
|
ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %lx\n", status);
|
|
|
|
pNtClose(subkey2);
|
|
pNtClose(subkey);
|
|
pNtClose(key);
|
|
}
|
|
|
|
static void test_notify(void)
|
|
{
|
|
OBJECT_ATTRIBUTES attr;
|
|
static const LARGE_INTEGER timeout;
|
|
IO_STATUS_BLOCK iosb;
|
|
UNICODE_STRING str;
|
|
HANDLE key, key2, events[4], subkey;
|
|
NTSTATUS status;
|
|
unsigned int i;
|
|
|
|
InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
|
|
status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
|
|
ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
|
|
status = pNtOpenKey(&key2, KEY_ALL_ACCESS, &attr);
|
|
ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\n", status);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(events); ++i)
|
|
events[i] = CreateEventW(NULL, TRUE, TRUE, NULL);
|
|
|
|
status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
status = pNtNotifyChangeKey(key2, events[2], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
status = pNtNotifyChangeKey(key2, events[3], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
|
|
status = WaitForMultipleObjects(4, events, FALSE, 0);
|
|
ok(status == WAIT_TIMEOUT, "got %ld\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%08lx\n", status);
|
|
pRtlFreeUnicodeString(&str);
|
|
|
|
status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[2], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[3], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
|
|
status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
|
|
status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[2], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[3], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
|
|
status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
|
|
status = WaitForMultipleObjects(4, events, FALSE, 0);
|
|
ok(status == WAIT_TIMEOUT, "got %ld\n", status);
|
|
|
|
status = pNtDeleteKey(subkey);
|
|
ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %lx\n", status);
|
|
|
|
status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[2], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[3], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
|
|
pNtClose(subkey);
|
|
|
|
status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE);
|
|
ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %lx\n", status);
|
|
|
|
pNtClose(key);
|
|
|
|
status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
|
|
ok(!status, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[2], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
status = pNtWaitForSingleObject(events[3], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "got %#lx\n", status);
|
|
|
|
if (pNtNotifyChangeMultipleKeys)
|
|
{
|
|
InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
|
|
status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr);
|
|
ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08lx\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 %lx\n", status);
|
|
|
|
status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
|
|
ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %lx\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%08lx\n", status);
|
|
pRtlFreeUnicodeString(&str);
|
|
|
|
status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
|
|
ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %lx\n", status);
|
|
|
|
status = pNtDeleteKey(subkey);
|
|
ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %lx\n", status);
|
|
pNtClose(subkey);
|
|
pNtClose(key);
|
|
}
|
|
else
|
|
{
|
|
win_skip("NtNotifyChangeMultipleKeys not available\n");
|
|
}
|
|
|
|
pNtClose(events[0]);
|
|
pNtClose(events[1]);
|
|
}
|
|
|
|
static void test_RtlCreateRegistryKey(void)
|
|
{
|
|
static WCHAR empty[] = {0};
|
|
static const WCHAR key1[] = {'\\','R','t','l','C','r','e','a','t','e','R','e','g','i','s','t','r','y','K','e','y',0};
|
|
UNICODE_STRING str;
|
|
SIZE_T size;
|
|
NTSTATUS status;
|
|
|
|
RtlDuplicateUnicodeString(1, &winetestpath, &str);
|
|
size = str.MaximumLength + sizeof(key1)* sizeof(WCHAR) * 2;
|
|
str.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, str.Buffer, size);
|
|
str.MaximumLength = size;
|
|
pRtlAppendUnicodeToString(&str, key1);
|
|
pRtlAppendUnicodeToString(&str, key1);
|
|
|
|
/* should work */
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer);
|
|
ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08lx\n", status);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, winetestpath.Buffer);
|
|
ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08lx\n", status);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_USER, NULL);
|
|
ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08lx\n", status);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL, NULL);
|
|
ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08lx\n", status);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_USER, empty);
|
|
ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08lx\n", status);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL, empty);
|
|
ok(status == STATUS_SUCCESS, "RtlCreateRegistryKey failed: %08lx\n", status);
|
|
|
|
/* invalid first parameter */
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_USER+1, winetestpath.Buffer);
|
|
ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_INVALID_PARAMETER);
|
|
|
|
status = pRtlCreateRegistryKey((RTL_REGISTRY_USER+1) | RTL_REGISTRY_OPTIONAL, winetestpath.Buffer);
|
|
ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_INVALID_PARAMETER);
|
|
|
|
/* invalid second parameter */
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, NULL);
|
|
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, NULL);
|
|
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, empty);
|
|
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, empty);
|
|
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_OBJECT_PATH_SYNTAX_BAD);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, str.Buffer);
|
|
ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_OBJECT_NAME_NOT_FOUND);
|
|
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, str.Buffer);
|
|
ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_OBJECT_NAME_NOT_FOUND);
|
|
|
|
/* both parameters invalid */
|
|
status = pRtlCreateRegistryKey(RTL_REGISTRY_USER+1, NULL);
|
|
ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_INVALID_PARAMETER);
|
|
|
|
status = pRtlCreateRegistryKey((RTL_REGISTRY_USER+1) | RTL_REGISTRY_OPTIONAL, NULL);
|
|
ok(status == STATUS_INVALID_PARAMETER, "RtlCreateRegistryKey unexpected return value: %08lx, expected %08lx\n", status, STATUS_INVALID_PARAMETER);
|
|
|
|
pRtlFreeUnicodeString(&str);
|
|
}
|
|
|
|
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_RtlCreateRegistryKey();
|
|
test_NtDeleteKey();
|
|
test_symlinks();
|
|
test_redirection();
|
|
|
|
pRtlFreeUnicodeString(&winetestpath);
|
|
|
|
FreeLibrary(hntdll);
|
|
}
|