2013-07-20 19:33:13 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS kernel-mode tests
|
|
|
|
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
|
|
|
* PURPOSE: Test for RtlQueryRegistryValues
|
2013-10-12 16:05:54 +00:00
|
|
|
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
2013-07-20 19:33:13 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define KMT_EMULATE_KERNEL
|
|
|
|
#include <kmt_test.h>
|
|
|
|
|
|
|
|
#ifndef RTL_NUMBER_OF
|
|
|
|
#define RTL_NUMBER_OF(x) (sizeof(x) / sizeof(x[0]))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
PCWSTR ValueName;
|
|
|
|
ULONG ValueType;
|
|
|
|
PVOID ValueData;
|
|
|
|
ULONG ValueLength;
|
|
|
|
} EXPECTED_VALUE, *PEXPECTED_VALUE;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
ULONG CurrentIndex;
|
|
|
|
EXPECTED_VALUE Values[20];
|
|
|
|
} EXPECTED_VALUES, *PEXPECTED_VALUES;
|
|
|
|
|
|
|
|
//static RTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
|
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
QueryRoutine(
|
|
|
|
_In_ PWSTR ValueName,
|
|
|
|
_In_ ULONG ValueType,
|
|
|
|
_In_ PVOID ValueData,
|
|
|
|
_In_ ULONG ValueLength,
|
|
|
|
_In_ PVOID Context,
|
|
|
|
_In_ PVOID EntryContext)
|
|
|
|
{
|
|
|
|
PEXPECTED_VALUES ExpectedValues = Context;
|
|
|
|
PEXPECTED_VALUE Expected;
|
|
|
|
SIZE_T EqualBytes;
|
|
|
|
|
|
|
|
ok(ExpectedValues->CurrentIndex < ExpectedValues->Count,
|
|
|
|
"Call number %lu, expected only %lu\n",
|
|
|
|
ExpectedValues->CurrentIndex, ExpectedValues->Count);
|
|
|
|
if (!skip(ExpectedValues->CurrentIndex < ExpectedValues->Count, "Out of bounds\n"))
|
|
|
|
{
|
|
|
|
Expected = &ExpectedValues->Values[ExpectedValues->CurrentIndex];
|
|
|
|
if (EntryContext)
|
|
|
|
ok_eq_pointer(EntryContext, Expected);
|
|
|
|
ok_eq_wstr(ValueName, Expected->ValueName);
|
|
|
|
ok_eq_ulong(ValueType, Expected->ValueType);
|
|
|
|
ok_eq_ulong(ValueLength, Expected->ValueLength);
|
|
|
|
EqualBytes = RtlCompareMemory(ValueData,
|
|
|
|
Expected->ValueData,
|
|
|
|
min(ValueLength, Expected->ValueLength));
|
|
|
|
ok_eq_size(EqualBytes, Expected->ValueLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExpectedValues->CurrentIndex++;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
TestRtlQueryRegistryValues(
|
|
|
|
_In_ HANDLE KeyHandle)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"TestValue");
|
|
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[] =
|
|
|
|
{
|
|
|
|
{ QueryRoutine, 0, L"TestValue", NULL, REG_NONE, NULL, 0 },
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
EXPECTED_VALUES Expected;
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
PWSTR Str;
|
|
|
|
ULONG Len;
|
|
|
|
} STR_AND_LEN;
|
|
|
|
#define CONST_STR_AND_LEN(d) { (d), sizeof(d) }
|
|
|
|
#define CSAL CONST_STR_AND_LEN
|
|
|
|
|
|
|
|
#define NO_AUTO_LEN 1
|
|
|
|
#define NO_DEFAULT 2
|
|
|
|
#define AUTO_DIFFERS 4
|
|
|
|
#define DEFAULT_DIFFERS 8
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
STR_AND_LEN Value;
|
|
|
|
ULONG ExpectedCount;
|
|
|
|
STR_AND_LEN Expected[20];
|
|
|
|
ULONG Flags;
|
|
|
|
ULONG DefaultExpectedCount;
|
|
|
|
STR_AND_LEN DefaultExpected[20];
|
|
|
|
|
|
|
|
} Tests[] =
|
|
|
|
{
|
|
|
|
{ { NULL, 0 }, 0, { { NULL, 0 } }, NO_AUTO_LEN | NO_DEFAULT },
|
|
|
|
{ CSAL(L""), 0, { { NULL, 0 } }, NO_AUTO_LEN },
|
|
|
|
{ CSAL(L"\0"), 1, { CSAL(L"") },
|
|
|
|
AUTO_DIFFERS | DEFAULT_DIFFERS, 0, { { NULL, 0 } } },
|
|
|
|
{ CSAL(L"String"), 1, { CSAL(L"String") }, NO_AUTO_LEN },
|
|
|
|
{ CSAL(L"String\0"), 1, { CSAL(L"String") } },
|
|
|
|
{ CSAL(L"String1\0String2"), 2, { CSAL(L"String1"), CSAL(L"String2") }, NO_AUTO_LEN },
|
|
|
|
{ CSAL(L"String1\0String2\0"), 2, { CSAL(L"String1"), CSAL(L"String2") } },
|
|
|
|
{ CSAL(L"String1\0\0String3"), 3, { CSAL(L"String1"), CSAL(L""), CSAL(L"String3") }, NO_AUTO_LEN },
|
|
|
|
{ CSAL(L"String1\0\0String3\0"), 3, { CSAL(L"String1"), CSAL(L""), CSAL(L"String3") },
|
|
|
|
AUTO_DIFFERS, 1, { CSAL(L"String1") } },
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DO_QUERY(ExpectedArray, ExpectedCount) do \
|
|
|
|
{ \
|
|
|
|
ULONG _i; \
|
2013-11-26 14:26:31 +00:00
|
|
|
ULONG _ExpectedCount = (ExpectedCount); \
|
|
|
|
for (_i = 0; _i < _ExpectedCount; _i++) \
|
2013-07-20 19:33:13 +00:00
|
|
|
{ \
|
|
|
|
Expected.Values[_i].ValueName = ValueName.Buffer; \
|
|
|
|
Expected.Values[_i].ValueType = REG_SZ; \
|
|
|
|
Expected.Values[_i].ValueData = (ExpectedArray)[_i].Str; \
|
|
|
|
Expected.Values[_i].ValueLength = (ExpectedArray)[_i].Len; \
|
|
|
|
} \
|
|
|
|
Expected.CurrentIndex = 0; \
|
2013-11-26 14:26:31 +00:00
|
|
|
Expected.Count = _ExpectedCount; \
|
|
|
|
if (_ExpectedCount == 1) \
|
2013-07-20 19:33:13 +00:00
|
|
|
QueryTable[0].EntryContext = &Expected.Values[0]; \
|
|
|
|
else \
|
|
|
|
QueryTable[0].EntryContext = NULL; \
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, \
|
|
|
|
(PCWSTR)KeyHandle, \
|
|
|
|
QueryTable, \
|
|
|
|
&Expected, \
|
|
|
|
NULL); \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_ulong(Expected.CurrentIndex, Expected.Count); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
ULONG TestCount = RTL_NUMBER_OF(Tests);
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
for (i = 0; i < TestCount; i++)
|
|
|
|
{
|
|
|
|
trace("Set: %lu\n", i);
|
|
|
|
Status = ZwSetValueKey(KeyHandle,
|
|
|
|
&ValueName,
|
|
|
|
0,
|
|
|
|
REG_MULTI_SZ,
|
|
|
|
Tests[i].Value.Str,
|
|
|
|
Tests[i].Value.Len);
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
|
|
|
|
DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete value to test default values */
|
|
|
|
Status = ZwDeleteValueKey(KeyHandle, &ValueName);
|
|
|
|
ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND,
|
|
|
|
"ZwDeleteValueKey returned %lx\n", Status);
|
|
|
|
|
|
|
|
/* Default: REG_NONE */
|
|
|
|
DO_QUERY((STR_AND_LEN *)NULL, 0);
|
|
|
|
|
|
|
|
for (i = 0; i < TestCount; i++)
|
|
|
|
{
|
|
|
|
if (Tests[i].Flags & NO_DEFAULT)
|
|
|
|
continue;
|
|
|
|
trace("Default: %lu\n", i);
|
|
|
|
QueryTable[0].DefaultType = REG_MULTI_SZ;
|
|
|
|
QueryTable[0].DefaultData = Tests[i].Value.Str;
|
|
|
|
QueryTable[0].DefaultLength = Tests[i].Value.Len;
|
|
|
|
|
|
|
|
if (Tests[i].Flags & DEFAULT_DIFFERS)
|
|
|
|
DO_QUERY(Tests[i].DefaultExpected, Tests[i].DefaultExpectedCount);
|
|
|
|
else
|
|
|
|
DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < TestCount; i++)
|
|
|
|
{
|
|
|
|
if (Tests[i].Flags & NO_AUTO_LEN)
|
|
|
|
continue;
|
|
|
|
trace("Auto: %lu\n", i);
|
|
|
|
QueryTable[0].DefaultType = REG_MULTI_SZ;
|
|
|
|
QueryTable[0].DefaultData = Tests[i].Value.Str;
|
|
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
|
|
|
|
if (Tests[i].Flags & AUTO_DIFFERS)
|
|
|
|
DO_QUERY(Tests[i].DefaultExpected, Tests[i].DefaultExpectedCount);
|
|
|
|
else
|
|
|
|
DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
START_TEST(RtlRegistry)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
UNICODE_STRING KeyName;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
HANDLE SoftwareHandle;
|
|
|
|
HANDLE KeyHandle;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&KeyName, L"\\Registry\\MACHINE\\Software");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&KeyName,
|
2015-09-19 21:46:40 +00:00
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
2013-07-20 19:33:13 +00:00
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(&SoftwareHandle,
|
|
|
|
KEY_CREATE_SUB_KEY,
|
|
|
|
&ObjectAttributes);
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
if (skip(NT_SUCCESS(Status) && SoftwareHandle != NULL, "No software key\n"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&KeyName, L"RtlRegistryKmtestKey");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&KeyName,
|
2015-09-19 21:46:40 +00:00
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
2013-07-20 19:33:13 +00:00
|
|
|
SoftwareHandle,
|
|
|
|
NULL);
|
|
|
|
Status = ZwCreateKey(&KeyHandle,
|
|
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE,
|
|
|
|
&ObjectAttributes,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
REG_OPTION_VOLATILE,
|
|
|
|
NULL);
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
|
|
|
|
if (!skip(NT_SUCCESS(Status) && KeyHandle != NULL, "No test key\n"))
|
|
|
|
{
|
|
|
|
TestRtlQueryRegistryValues(KeyHandle);
|
|
|
|
|
|
|
|
Status = ZwDeleteKey(KeyHandle);
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
Status = ZwClose(KeyHandle);
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|