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