1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Tests for the NtQueryKey API 5 * PROGRAMMER: Jérôme Gardou <jerome.gardou@reactos.org> 6 * Thomas Faber <thomas.faber@reactos.org> 7 */ 8 9 #include "precomp.h" 10 11 static 12 void 13 Test_KeyFullInformation(void) 14 { 15 UNICODE_STRING HKLM_Name = RTL_CONSTANT_STRING(L"\\Registry\\Machine"); 16 UNICODE_STRING Software_Name = RTL_CONSTANT_STRING(L"Software"); 17 UNICODE_STRING Test_Name = RTL_CONSTANT_STRING(L"NtQueryKey_apitest"); 18 UNICODE_STRING MyClass = RTL_CONSTANT_STRING(L"MyClass"); 19 HANDLE HKLM_Key, HKLM_Software_Key, Test_Key; 20 ULONG FullInformationLength; 21 PKEY_FULL_INFORMATION FullInformation; 22 ULONG InfoLength; 23 OBJECT_ATTRIBUTES ObjectAttributes; 24 NTSTATUS Status; 25 26 FullInformationLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class[100]); 27 FullInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, FullInformationLength); 28 if (!FullInformation) 29 { 30 skip("Out of memory\n"); 31 return; 32 } 33 34 InitializeObjectAttributes(&ObjectAttributes, 35 &HKLM_Name, 36 OBJ_CASE_INSENSITIVE, 37 NULL, 38 NULL); 39 Status = NtOpenKey(&HKLM_Key, KEY_READ, &ObjectAttributes); 40 ok_ntstatus(Status, STATUS_SUCCESS); 41 42 InfoLength = 0x55555555; 43 Status = NtQueryKey(HKLM_Key, KeyFullInformation, NULL, 0, &InfoLength); 44 ok(Status == STATUS_BUFFER_TOO_SMALL, "Status = 0x%lx\n", Status); 45 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength); 46 47 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 48 InfoLength = 0x55555555; 49 Status = NtQueryKey(HKLM_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class), &InfoLength); 50 ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status); 51 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength); 52 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 53 ok(FullInformation->TitleIndex == 0, "TitleIndex = %lu\n", FullInformation->TitleIndex); 54 ok(FullInformation->ClassOffset == 0xffffffff, "ClassOffset = %lu\n", FullInformation->ClassOffset); 55 ok(FullInformation->ClassLength == 0, "ClassLength = %lu\n", FullInformation->ClassLength); 56 ok(FullInformation->SubKeys >= 5 && FullInformation->SubKeys < 20, "SubKeys = %lu\n", FullInformation->SubKeys); 57 ok(FullInformation->MaxNameLen >= 8 * sizeof(WCHAR) && FullInformation->MaxNameLen < 100 * sizeof(WCHAR), "MaxNameLen = %lu\n", FullInformation->MaxNameLen); 58 ok(FullInformation->MaxClassLen != 0x55555555 && FullInformation->MaxClassLen % sizeof(WCHAR) == 0, "MaxClassLen = %lu\n", FullInformation->MaxClassLen); 59 ok(FullInformation->Values != 0x55555555, "Values = %lu\n", FullInformation->Values); 60 ok(FullInformation->MaxValueNameLen != 0x55555555 && FullInformation->MaxValueNameLen % sizeof(WCHAR) == 0, "MaxValueNameLen = %lu\n", FullInformation->MaxValueNameLen); 61 ok(FullInformation->MaxValueDataLen != 0x55555555, "MaxValueDataLen = %lu\n", FullInformation->MaxValueDataLen); 62 ok(FullInformation->Class[0] == 0x5555, "Class[0] = %u\n", FullInformation->Class[0]); 63 64 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 65 InfoLength = 0x55555555; 66 Status = NtQueryKey(HKLM_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) - 1, &InfoLength); 67 ok(Status == STATUS_BUFFER_TOO_SMALL, "Status = 0x%lx\n", Status); 68 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength); 69 ok(FullInformation->LastWriteTime.QuadPart == 0x5555555555555555, "LastWriteTime changed: %I64d\n", FullInformation->LastWriteTime.QuadPart); 70 71 InitializeObjectAttributes(&ObjectAttributes, 72 &Software_Name, 73 OBJ_CASE_INSENSITIVE, 74 HKLM_Key, 75 NULL); 76 Status = NtOpenKey(&HKLM_Software_Key, KEY_READ, &ObjectAttributes); 77 ok_ntstatus(Status, STATUS_SUCCESS); 78 79 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 80 InfoLength = 0x55555555; 81 Status = NtQueryKey(HKLM_Software_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class), &InfoLength); 82 ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status); 83 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "InfoLength = %lu\n", InfoLength); 84 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 85 ok(FullInformation->TitleIndex == 0, "TitleIndex = %lu\n", FullInformation->TitleIndex); 86 ok(FullInformation->ClassOffset == 0xffffffff, "ClassOffset = %lu\n", FullInformation->ClassOffset); 87 ok(FullInformation->ClassLength == 0, "ClassLength = %lu\n", FullInformation->ClassLength); 88 ok(FullInformation->SubKeys >= 5 && FullInformation->SubKeys < 1000, "SubKeys = %lu\n", FullInformation->SubKeys); 89 ok(FullInformation->MaxNameLen >= 8 * sizeof(WCHAR), "MaxNameLen = %lu\n", FullInformation->MaxNameLen); 90 ok(FullInformation->MaxClassLen != 0x55555555 && FullInformation->MaxClassLen % sizeof(WCHAR) == 0, "MaxClassLen = %lu\n", FullInformation->MaxClassLen); 91 ok(FullInformation->Values != 0x55555555, "Values = %lu\n", FullInformation->Values); 92 ok(FullInformation->MaxValueNameLen != 0x55555555 && FullInformation->MaxValueNameLen % sizeof(WCHAR) == 0, "MaxValueNameLen = %lu\n", FullInformation->MaxValueNameLen); 93 ok(FullInformation->MaxValueDataLen != 0x55555555, "MaxValueDataLen = %lu\n", FullInformation->MaxValueDataLen); 94 ok(FullInformation->Class[0] == 0x5555, "Class[0] = %u\n", FullInformation->Class[0]); 95 96 InitializeObjectAttributes(&ObjectAttributes, 97 &Test_Name, 98 OBJ_CASE_INSENSITIVE, 99 HKLM_Software_Key, 100 NULL); 101 Status = NtCreateKey(&Test_Key, KEY_ALL_ACCESS, &ObjectAttributes, 0, &MyClass, REG_OPTION_VOLATILE, NULL); 102 ok_ntstatus(Status, STATUS_SUCCESS); 103 104 InfoLength = 0x55555555; 105 Status = NtQueryKey(Test_Key, KeyFullInformation, NULL, 0, &InfoLength); 106 ok(Status == STATUS_BUFFER_TOO_SMALL, "Status = 0x%lx\n", Status); 107 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength); 108 109 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 110 InfoLength = 0x55555555; 111 Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class), &InfoLength); 112 ok(Status == STATUS_BUFFER_OVERFLOW, "Status = 0x%lx\n", Status); 113 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength); 114 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 115 ok(FullInformation->TitleIndex == 0, "TitleIndex = %lu\n", FullInformation->TitleIndex); 116 ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset); 117 ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength); 118 ok(FullInformation->SubKeys == 0, "SubKeys = %lu\n", FullInformation->SubKeys); 119 ok(FullInformation->MaxNameLen == 0, "MaxNameLen = %lu\n", FullInformation->MaxNameLen); 120 ok(FullInformation->MaxClassLen == 0, "MaxClassLen = %lu\n", FullInformation->MaxClassLen); 121 ok(FullInformation->Values == 0, "Values = %lu\n", FullInformation->Values); 122 ok(FullInformation->MaxValueNameLen == 0, "MaxValueNameLen = %lu\n", FullInformation->MaxValueNameLen); 123 ok(FullInformation->MaxValueDataLen == 0, "MaxValueDataLen = %lu\n", FullInformation->MaxValueDataLen); 124 ok(FullInformation->Class[0] == 0x5555, "Class[0] = %u\n", FullInformation->Class[0]); 125 126 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 127 InfoLength = 0x55555555; 128 Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class[1]), &InfoLength); 129 ok(Status == STATUS_BUFFER_OVERFLOW, "Status = 0x%lx\n", Status); 130 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength); 131 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 132 ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset); 133 ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength); 134 ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]); 135 ok(FullInformation->Class[1] == 0x5555, "Class[1] = %u\n", FullInformation->Class[1]); 136 137 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 138 InfoLength = 0x55555555; 139 Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length - 1, &InfoLength); 140 ok(Status == STATUS_BUFFER_OVERFLOW, "Status = 0x%lx\n", Status); 141 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength); 142 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 143 ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset); 144 ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength); 145 ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]); 146 ok(FullInformation->Class[1] == L'y', "Class[1] = %u\n", FullInformation->Class[1]); 147 ok(FullInformation->Class[6] == (L's' | 0x5500), "Class[6] = %u\n", FullInformation->Class[6]); 148 ok(FullInformation->Class[7] == 0x5555, "Class[7] = %u\n", FullInformation->Class[7]); 149 150 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 151 InfoLength = 0x55555555; 152 Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, &InfoLength); 153 ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status); 154 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength); 155 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 156 ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset); 157 ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength); 158 ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]); 159 ok(FullInformation->Class[1] == L'y', "Class[1] = %u\n", FullInformation->Class[1]); 160 ok(FullInformation->Class[6] == L's', "Class[6] = %u\n", FullInformation->Class[6]); 161 ok(FullInformation->Class[7] == 0x5555, "Class[7] = %u\n", FullInformation->Class[7]); 162 163 RtlFillMemory(FullInformation, FullInformationLength, 0x55); 164 InfoLength = 0x55555555; 165 Status = NtQueryKey(Test_Key, KeyFullInformation, FullInformation, FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length + sizeof(UNICODE_NULL), &InfoLength); 166 ok(Status == STATUS_SUCCESS, "Status = 0x%lx\n", Status); 167 ok(InfoLength == FIELD_OFFSET(KEY_FULL_INFORMATION, Class) + MyClass.Length, "InfoLength = %lu\n", InfoLength); 168 ok(FullInformation->LastWriteTime.QuadPart != 0x5555555555555555, "LastWriteTime unchanged\n"); 169 ok(FullInformation->ClassOffset == FIELD_OFFSET(KEY_FULL_INFORMATION, Class), "ClassOffset = %lu\n", FullInformation->ClassOffset); 170 ok(FullInformation->ClassLength == MyClass.Length, "ClassLength = %lu\n", FullInformation->ClassLength); 171 ok(FullInformation->Class[0] == L'M', "Class[0] = %u\n", FullInformation->Class[0]); 172 ok(FullInformation->Class[1] == L'y', "Class[1] = %u\n", FullInformation->Class[1]); 173 ok(FullInformation->Class[6] == L's', "Class[6] = %u\n", FullInformation->Class[6]); 174 ok(FullInformation->Class[7] == 0x5555, "Class[7] = %u\n", FullInformation->Class[7]); 175 176 RtlFreeHeap(RtlGetProcessHeap(), 0, FullInformation); 177 178 Status = NtDeleteKey(Test_Key); 179 ok_ntstatus(Status, STATUS_SUCCESS); 180 181 NtClose(Test_Key); 182 NtClose(HKLM_Software_Key); 183 NtClose(HKLM_Key); 184 } 185 186 static 187 void 188 Test_KeyNameInformation(void) 189 { 190 UNICODE_STRING HKLM_Name = RTL_CONSTANT_STRING(L"\\Registry\\Machine"); 191 UNICODE_STRING HKLM_Software_Name = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software"); 192 UNICODE_STRING Software_Name = RTL_CONSTANT_STRING(L"Software"); 193 UNICODE_STRING InfoName; 194 HANDLE HKLM_Key, HKLM_Software_Key; 195 PKEY_NAME_INFORMATION NameInformation; 196 ULONG InfoLength; 197 OBJECT_ATTRIBUTES ObjectAttributes; 198 NTSTATUS Status; 199 200 /* Open the HKCU key */ 201 InitializeObjectAttributes(&ObjectAttributes, 202 &HKLM_Name, 203 OBJ_CASE_INSENSITIVE, 204 NULL, 205 NULL); 206 Status = NtOpenKey(&HKLM_Key, KEY_READ, &ObjectAttributes); 207 ok_ntstatus(Status, STATUS_SUCCESS); 208 209 /* Get the name info length */ 210 InfoLength = 0; 211 Status = NtQueryKey(HKLM_Key, KeyNameInformation, NULL, 0, &InfoLength); 212 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 213 ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Name.Length/sizeof(WCHAR)])); 214 215 /* Get it for real */ 216 NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength); 217 if (!NameInformation) 218 { 219 skip("Out of memory\n"); 220 return; 221 } 222 223 Status = NtQueryKey(HKLM_Key, KeyNameInformation, NameInformation, InfoLength, &InfoLength); 224 ok_ntstatus(Status, STATUS_SUCCESS); 225 ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Name.Length/sizeof(WCHAR)])); 226 ok_size_t(NameInformation->NameLength, HKLM_Name.Length); 227 228 InfoName.Buffer = NameInformation->Name; 229 InfoName.Length = NameInformation->NameLength; 230 InfoName.MaximumLength = NameInformation->NameLength; 231 ok(RtlCompareUnicodeString(&InfoName, &HKLM_Name, TRUE) == 0, "%.*S\n", 232 InfoName.Length, InfoName.Buffer); 233 234 RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation); 235 236 /* Open one subkey */ 237 InitializeObjectAttributes(&ObjectAttributes, 238 &Software_Name, 239 OBJ_CASE_INSENSITIVE, 240 HKLM_Key, 241 NULL); 242 Status = NtOpenKey(&HKLM_Software_Key, KEY_READ, &ObjectAttributes); 243 ok_ntstatus(Status, STATUS_SUCCESS); 244 245 /* Get the name info length */ 246 InfoLength = 0; 247 Status = NtQueryKey(HKLM_Software_Key, KeyNameInformation, NULL, 0, &InfoLength); 248 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 249 ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Software_Name.Length/sizeof(WCHAR)])); 250 251 /* Get it for real */ 252 NameInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength); 253 ok(NameInformation != NULL, "\n"); 254 255 Status = NtQueryKey(HKLM_Software_Key, KeyNameInformation, NameInformation, InfoLength, &InfoLength); 256 ok_ntstatus(Status, STATUS_SUCCESS); 257 ok_size_t(InfoLength, FIELD_OFFSET(KEY_NAME_INFORMATION, Name[HKLM_Software_Name.Length/sizeof(WCHAR)])); 258 ok_size_t(NameInformation->NameLength, HKLM_Software_Name.Length); 259 260 InfoName.Buffer = NameInformation->Name; 261 InfoName.Length = NameInformation->NameLength; 262 InfoName.MaximumLength = NameInformation->NameLength; 263 ok(RtlCompareUnicodeString(&InfoName, &HKLM_Software_Name, TRUE) == 0, "%.*S\n", 264 InfoName.Length, InfoName.Buffer); 265 266 RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation); 267 268 NtClose(HKLM_Software_Key); 269 NtClose(HKLM_Key); 270 } 271 272 START_TEST(NtQueryKey) 273 { 274 Test_KeyFullInformation(); 275 Test_KeyNameInformation(); 276 } 277