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>
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>
19 Test_KeyFullInformation(void)
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
;
29 OBJECT_ATTRIBUTES ObjectAttributes
;
32 FullInformationLength
= FIELD_OFFSET(KEY_FULL_INFORMATION
, Class
[100]);
33 FullInformation
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FullInformationLength
);
36 skip("Out of memory\n");
40 InitializeObjectAttributes(&ObjectAttributes
,
45 Status
= NtOpenKey(&HKLM_Key
, KEY_READ
, &ObjectAttributes
);
46 ok_ntstatus(Status
, STATUS_SUCCESS
);
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
);
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]);
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
);
77 InitializeObjectAttributes(&ObjectAttributes
,
82 Status
= NtOpenKey(&HKLM_Software_Key
, KEY_READ
, &ObjectAttributes
);
83 ok_ntstatus(Status
, STATUS_SUCCESS
);
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]);
102 InitializeObjectAttributes(&ObjectAttributes
,
104 OBJ_CASE_INSENSITIVE
,
107 Status
= NtCreateKey(&Test_Key
, KEY_ALL_ACCESS
, &ObjectAttributes
, 0, &MyClass
, REG_OPTION_VOLATILE
, NULL
);
108 ok_ntstatus(Status
, STATUS_SUCCESS
);
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
);
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]);
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]);
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]);
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]);
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]);
182 RtlFreeHeap(RtlGetProcessHeap(), 0, FullInformation
);
184 Status
= NtDeleteKey(Test_Key
);
185 ok_ntstatus(Status
, STATUS_SUCCESS
);
188 NtClose(HKLM_Software_Key
);
194 Test_KeyNameInformation(void)
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
;
203 OBJECT_ATTRIBUTES ObjectAttributes
;
206 /* Open the HKCU key */
207 InitializeObjectAttributes(&ObjectAttributes
,
209 OBJ_CASE_INSENSITIVE
,
212 Status
= NtOpenKey(&HKLM_Key
, KEY_READ
, &ObjectAttributes
);
213 ok_ntstatus(Status
, STATUS_SUCCESS
);
215 /* Get the name info length */
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
)]));
221 /* Get it for real */
222 NameInformation
= RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength
);
223 if (!NameInformation
)
225 skip("Out of memory\n");
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
);
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
);
240 RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation
);
242 /* Open one subkey */
243 InitializeObjectAttributes(&ObjectAttributes
,
245 OBJ_CASE_INSENSITIVE
,
248 Status
= NtOpenKey(&HKLM_Software_Key
, KEY_READ
, &ObjectAttributes
);
249 ok_ntstatus(Status
, STATUS_SUCCESS
);
251 /* Get the name info length */
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
)]));
257 /* Get it for real */
258 NameInformation
= RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength
);
259 ok(NameInformation
!= NULL
, "\n");
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
);
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
);
272 RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation
);
274 NtClose(HKLM_Software_Key
);
278 START_TEST(NtQueryKey
)
280 Test_KeyFullInformation();
281 Test_KeyNameInformation();