ntdll: Added KeyCachedInformation key info class implementation.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3d5db6bdf5
commit
5eb3035374
|
@ -261,6 +261,7 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i
|
|||
case KeyFullInformation: data_ptr = ((KEY_FULL_INFORMATION *)info)->Class; break;
|
||||
case KeyNodeInformation: data_ptr = ((KEY_NODE_INFORMATION *)info)->Name; break;
|
||||
case KeyNameInformation: data_ptr = ((KEY_NAME_INFORMATION *)info)->Name; break;
|
||||
case KeyCachedInformation: data_ptr = ((KEY_CACHED_INFORMATION *)info)+1; break;
|
||||
default:
|
||||
FIXME( "Information class %d not implemented\n", info_class );
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
@ -332,6 +333,23 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i
|
|||
memcpy( info, &keyinfo, min( length, fixed_size ) );
|
||||
}
|
||||
break;
|
||||
case KeyCachedInformation:
|
||||
{
|
||||
KEY_CACHED_INFORMATION keyinfo;
|
||||
fixed_size = sizeof(keyinfo);
|
||||
keyinfo.LastWriteTime.QuadPart = reply->modif;
|
||||
keyinfo.TitleIndex = 0;
|
||||
keyinfo.SubKeys = reply->subkeys;
|
||||
keyinfo.MaxNameLen = reply->max_subkey;
|
||||
keyinfo.Values = reply->values;
|
||||
keyinfo.MaxValueNameLen = reply->max_value;
|
||||
keyinfo.MaxValueDataLen = reply->max_data;
|
||||
keyinfo.NameLength = reply->namelen;
|
||||
memcpy( info, &keyinfo, min( length, fixed_size ) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*result_len = fixed_size + reply->total;
|
||||
if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW;
|
||||
|
|
|
@ -1466,12 +1466,14 @@ static void test_long_value_name(void)
|
|||
|
||||
static void test_NtQueryKey(void)
|
||||
{
|
||||
HANDLE key;
|
||||
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);
|
||||
|
@ -1506,6 +1508,59 @@ static void test_NtQueryKey(void)
|
|||
wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, info);
|
||||
|
||||
attr.RootDirectory = key;
|
||||
attr.ObjectName = &str;
|
||||
pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey");
|
||||
status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0);
|
||||
ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
|
||||
|
||||
status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
|
||||
ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
|
||||
ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
|
||||
ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
|
||||
ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values);
|
||||
ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
|
||||
ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
|
||||
ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
|
||||
}
|
||||
|
||||
attr.RootDirectory = subkey;
|
||||
attr.ObjectName = &str;
|
||||
pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2");
|
||||
status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0);
|
||||
ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
|
||||
|
||||
pRtlCreateUnicodeStringFromAsciiz(&str, "val");
|
||||
dw = 64;
|
||||
status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status );
|
||||
|
||||
status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len);
|
||||
ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
ok(len == sizeof(cached_info), "got unexpected length %d\n", len);
|
||||
ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys);
|
||||
ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen);
|
||||
ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values);
|
||||
ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen);
|
||||
ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen);
|
||||
ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength);
|
||||
}
|
||||
|
||||
status = pNtDeleteKey(subkey2);
|
||||
ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
|
||||
status = pNtDeleteKey(subkey);
|
||||
ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
|
||||
|
||||
pNtClose(subkey2);
|
||||
pNtClose(subkey);
|
||||
pNtClose(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -696,7 +696,12 @@ typedef enum _KEY_INFORMATION_CLASS {
|
|||
KeyBasicInformation,
|
||||
KeyNodeInformation,
|
||||
KeyFullInformation,
|
||||
KeyNameInformation
|
||||
KeyNameInformation,
|
||||
KeyCachedInformation,
|
||||
KeyFlagsInformation,
|
||||
KeyVirtualizationInformation,
|
||||
KeyHandleTagsInformation,
|
||||
MaxKeyInfoClass
|
||||
} KEY_INFORMATION_CLASS;
|
||||
|
||||
typedef enum _KEY_VALUE_INFORMATION_CLASS {
|
||||
|
@ -1024,6 +1029,18 @@ typedef struct _KEY_NAME_INFORMATION {
|
|||
WCHAR Name[1];
|
||||
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
|
||||
|
||||
typedef struct _KEY_CACHED_INFORMATION
|
||||
{
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
ULONG TitleIndex;
|
||||
ULONG SubKeys;
|
||||
ULONG MaxNameLen;
|
||||
ULONG Values;
|
||||
ULONG MaxValueNameLen;
|
||||
ULONG MaxValueDataLen;
|
||||
ULONG NameLength;
|
||||
} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION;
|
||||
|
||||
typedef struct _KEY_VALUE_ENTRY
|
||||
{
|
||||
PUNICODE_STRING ValueName;
|
||||
|
|
|
@ -906,6 +906,7 @@ static void enum_key( const struct key *key, int index, int info_class,
|
|||
reply->max_data = 0;
|
||||
break;
|
||||
case KeyFullInformation:
|
||||
case KeyCachedInformation:
|
||||
for (i = 0; i <= key->last_subkey; i++)
|
||||
{
|
||||
if (key->subkeys[i]->namelen > max_subkey) max_subkey = key->subkeys[i]->namelen;
|
||||
|
@ -920,7 +921,10 @@ static void enum_key( const struct key *key, int index, int info_class,
|
|||
reply->max_class = max_class;
|
||||
reply->max_value = max_value;
|
||||
reply->max_data = max_data;
|
||||
namelen = 0; /* only return the class */
|
||||
reply->namelen = namelen;
|
||||
if (info_class == KeyCachedInformation)
|
||||
classlen = 0; /* don't return any data, only its size */
|
||||
namelen = 0; /* don't return name */
|
||||
break;
|
||||
default:
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
|
|
Loading…
Reference in New Issue