1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Test for RtlQueryRegistryValues 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #define KMT_EMULATE_KERNEL 9 #include <kmt_test.h> 10 11 #ifndef RTL_NUMBER_OF 12 #define RTL_NUMBER_OF(x) (sizeof(x) / sizeof(x[0])) 13 #endif 14 15 typedef struct 16 { 17 PCWSTR ValueName; 18 ULONG ValueType; 19 PVOID ValueData; 20 ULONG ValueLength; 21 } EXPECTED_VALUE, *PEXPECTED_VALUE; 22 23 typedef struct 24 { 25 ULONG Count; 26 ULONG CurrentIndex; 27 EXPECTED_VALUE Values[20]; 28 } EXPECTED_VALUES, *PEXPECTED_VALUES; 29 30 //static RTL_QUERY_REGISTRY_ROUTINE QueryRoutine; 31 static 32 NTSTATUS 33 NTAPI 34 QueryRoutine( 35 _In_ PWSTR ValueName, 36 _In_ ULONG ValueType, 37 _In_ PVOID ValueData, 38 _In_ ULONG ValueLength, 39 _In_ PVOID Context, 40 _In_ PVOID EntryContext) 41 { 42 PEXPECTED_VALUES ExpectedValues = Context; 43 PEXPECTED_VALUE Expected; 44 SIZE_T EqualBytes; 45 46 ok(ExpectedValues->CurrentIndex < ExpectedValues->Count, 47 "Call number %lu, expected only %lu\n", 48 ExpectedValues->CurrentIndex, ExpectedValues->Count); 49 if (!skip(ExpectedValues->CurrentIndex < ExpectedValues->Count, "Out of bounds\n")) 50 { 51 Expected = &ExpectedValues->Values[ExpectedValues->CurrentIndex]; 52 if (EntryContext) 53 ok_eq_pointer(EntryContext, Expected); 54 ok_eq_wstr(ValueName, Expected->ValueName); 55 ok_eq_ulong(ValueType, Expected->ValueType); 56 ok_eq_ulong(ValueLength, Expected->ValueLength); 57 EqualBytes = RtlCompareMemory(ValueData, 58 Expected->ValueData, 59 min(ValueLength, Expected->ValueLength)); 60 ok_eq_size(EqualBytes, Expected->ValueLength); 61 } 62 63 ExpectedValues->CurrentIndex++; 64 return STATUS_SUCCESS; 65 } 66 67 static 68 VOID 69 TestRtlQueryRegistryValues( 70 _In_ HANDLE KeyHandle) 71 { 72 NTSTATUS Status; 73 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"TestValue"); 74 RTL_QUERY_REGISTRY_TABLE QueryTable[] = 75 { 76 { QueryRoutine, 0, L"TestValue", NULL, REG_NONE, NULL, 0 }, 77 { NULL } 78 }; 79 EXPECTED_VALUES Expected; 80 typedef struct 81 { 82 PWSTR Str; 83 ULONG Len; 84 } STR_AND_LEN; 85 #define CONST_STR_AND_LEN(d) { (d), sizeof(d) } 86 #define CSAL CONST_STR_AND_LEN 87 88 #define NO_AUTO_LEN 1 89 #define NO_DEFAULT 2 90 #define AUTO_DIFFERS 4 91 #define DEFAULT_DIFFERS 8 92 struct 93 { 94 STR_AND_LEN Value; 95 ULONG ExpectedCount; 96 STR_AND_LEN Expected[20]; 97 ULONG Flags; 98 ULONG DefaultExpectedCount; 99 STR_AND_LEN DefaultExpected[20]; 100 101 } Tests[] = 102 { 103 { { NULL, 0 }, 0, { { NULL, 0 } }, NO_AUTO_LEN | NO_DEFAULT }, 104 { CSAL(L""), 0, { { NULL, 0 } }, NO_AUTO_LEN }, 105 { CSAL(L"\0"), 1, { CSAL(L"") }, 106 AUTO_DIFFERS | DEFAULT_DIFFERS, 0, { { NULL, 0 } } }, 107 { CSAL(L"String"), 1, { CSAL(L"String") }, NO_AUTO_LEN }, 108 { CSAL(L"String\0"), 1, { CSAL(L"String") } }, 109 { CSAL(L"String1\0String2"), 2, { CSAL(L"String1"), CSAL(L"String2") }, NO_AUTO_LEN }, 110 { CSAL(L"String1\0String2\0"), 2, { CSAL(L"String1"), CSAL(L"String2") } }, 111 { CSAL(L"String1\0\0String3"), 3, { CSAL(L"String1"), CSAL(L""), CSAL(L"String3") }, NO_AUTO_LEN }, 112 { CSAL(L"String1\0\0String3\0"), 3, { CSAL(L"String1"), CSAL(L""), CSAL(L"String3") }, 113 AUTO_DIFFERS, 1, { CSAL(L"String1") } }, 114 }; 115 116 #define DO_QUERY(ExpectedArray, ExpectedCount) do \ 117 { \ 118 ULONG _i; \ 119 ULONG _ExpectedCount = (ExpectedCount); \ 120 for (_i = 0; _i < _ExpectedCount; _i++) \ 121 { \ 122 Expected.Values[_i].ValueName = ValueName.Buffer; \ 123 Expected.Values[_i].ValueType = REG_SZ; \ 124 Expected.Values[_i].ValueData = (ExpectedArray)[_i].Str; \ 125 Expected.Values[_i].ValueLength = (ExpectedArray)[_i].Len; \ 126 } \ 127 Expected.CurrentIndex = 0; \ 128 Expected.Count = _ExpectedCount; \ 129 if (_ExpectedCount == 1) \ 130 QueryTable[0].EntryContext = &Expected.Values[0]; \ 131 else \ 132 QueryTable[0].EntryContext = NULL; \ 133 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, \ 134 (PCWSTR)KeyHandle, \ 135 QueryTable, \ 136 &Expected, \ 137 NULL); \ 138 ok_eq_hex(Status, STATUS_SUCCESS); \ 139 ok_eq_ulong(Expected.CurrentIndex, Expected.Count); \ 140 } while(0) 141 142 ULONG TestCount = RTL_NUMBER_OF(Tests); 143 ULONG i; 144 145 for (i = 0; i < TestCount; i++) 146 { 147 trace("Set: %lu\n", i); 148 Status = ZwSetValueKey(KeyHandle, 149 &ValueName, 150 0, 151 REG_MULTI_SZ, 152 Tests[i].Value.Str, 153 Tests[i].Value.Len); 154 ok_eq_hex(Status, STATUS_SUCCESS); 155 156 DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount); 157 } 158 159 /* Delete value to test default values */ 160 Status = ZwDeleteValueKey(KeyHandle, &ValueName); 161 ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND, 162 "ZwDeleteValueKey returned %lx\n", Status); 163 164 /* Default: REG_NONE */ 165 DO_QUERY((STR_AND_LEN *)NULL, 0); 166 167 for (i = 0; i < TestCount; i++) 168 { 169 if (Tests[i].Flags & NO_DEFAULT) 170 continue; 171 trace("Default: %lu\n", i); 172 QueryTable[0].DefaultType = REG_MULTI_SZ; 173 QueryTable[0].DefaultData = Tests[i].Value.Str; 174 QueryTable[0].DefaultLength = Tests[i].Value.Len; 175 176 if (Tests[i].Flags & DEFAULT_DIFFERS) 177 DO_QUERY(Tests[i].DefaultExpected, Tests[i].DefaultExpectedCount); 178 else 179 DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount); 180 } 181 182 for (i = 0; i < TestCount; i++) 183 { 184 if (Tests[i].Flags & NO_AUTO_LEN) 185 continue; 186 trace("Auto: %lu\n", i); 187 QueryTable[0].DefaultType = REG_MULTI_SZ; 188 QueryTable[0].DefaultData = Tests[i].Value.Str; 189 QueryTable[0].DefaultLength = 0; 190 191 if (Tests[i].Flags & AUTO_DIFFERS) 192 DO_QUERY(Tests[i].DefaultExpected, Tests[i].DefaultExpectedCount); 193 else 194 DO_QUERY(Tests[i].Expected, Tests[i].ExpectedCount); 195 } 196 } 197 198 START_TEST(RtlRegistry) 199 { 200 NTSTATUS Status; 201 UNICODE_STRING KeyName; 202 OBJECT_ATTRIBUTES ObjectAttributes; 203 HANDLE SoftwareHandle; 204 HANDLE KeyHandle; 205 206 RtlInitUnicodeString(&KeyName, L"\\Registry\\MACHINE\\Software"); 207 InitializeObjectAttributes(&ObjectAttributes, 208 &KeyName, 209 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 210 NULL, 211 NULL); 212 Status = ZwOpenKey(&SoftwareHandle, 213 KEY_CREATE_SUB_KEY, 214 &ObjectAttributes); 215 ok_eq_hex(Status, STATUS_SUCCESS); 216 if (skip(NT_SUCCESS(Status) && SoftwareHandle != NULL, "No software key\n")) 217 return; 218 219 RtlInitUnicodeString(&KeyName, L"RtlRegistryKmtestKey"); 220 InitializeObjectAttributes(&ObjectAttributes, 221 &KeyName, 222 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 223 SoftwareHandle, 224 NULL); 225 Status = ZwCreateKey(&KeyHandle, 226 KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, 227 &ObjectAttributes, 228 0, 229 NULL, 230 REG_OPTION_VOLATILE, 231 NULL); 232 ok_eq_hex(Status, STATUS_SUCCESS); 233 234 if (!skip(NT_SUCCESS(Status) && KeyHandle != NULL, "No test key\n")) 235 { 236 TestRtlQueryRegistryValues(KeyHandle); 237 238 Status = ZwDeleteKey(KeyHandle); 239 ok_eq_hex(Status, STATUS_SUCCESS); 240 Status = ZwClose(KeyHandle); 241 ok_eq_hex(Status, STATUS_SUCCESS); 242 } 243 } 244