2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for the HKEY_CLASSES_ROOT key
5 * PROGRAMMER: Jérôme Gardou <jerome.gardou@reactos.org>
10 #define WIN32_NO_STATUS
12 #include <ndk/rtlfuncs.h>
13 #include <ndk/cmfuncs.h>
14 #include <ndk/cmtypes.h>
16 #define IS_HKCR(hk) (((UINT_PTR)hk & 3) == 2)
18 /* HKCU and HKLM system paths */
19 static UNICODE_STRING HKLM_ClassesPath
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\Software\\Classes");
20 static UNICODE_STRING HKCU_ClassesPath
;
24 DeleteSubKey(HKEY hKey
, LPWSTR Root
, LPWSTR SubKey
)
29 ErrorCode
= RegOpenKeyExW(
35 ok_dec(ErrorCode
, ERROR_SUCCESS
);
36 ErrorCode
= RegDeleteKeyW(RootKey
, SubKey
);
44 GetKeyName(HKEY hKey
, PUNICODE_STRING KeyName
)
46 UNICODE_STRING InfoName
;
47 PKEY_NAME_INFORMATION NameInformation
;
53 Status
= NtQueryKey(hKey
, KeyNameInformation
, NULL
, 0, &InfoLength
);
54 ok_ntstatus(Status
, STATUS_BUFFER_TOO_SMALL
);
57 NameInformation
= RtlAllocateHeap(RtlGetProcessHeap(), 0, InfoLength
);
58 ok(NameInformation
!= NULL
, "\n");
60 Status
= NtQueryKey(hKey
, KeyNameInformation
, NameInformation
, InfoLength
, &InfoLength
);
61 ok_ntstatus(Status
, STATUS_SUCCESS
);
63 InfoName
.Buffer
= NameInformation
->Name
;
64 InfoName
.Length
= NameInformation
->NameLength
;
65 InfoName
.MaximumLength
= InfoName
.Length
;
67 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
, &InfoName
, KeyName
);
69 RtlFreeHeap(RtlGetProcessHeap(), 0, NameInformation
);
72 static void _test_key_deleted(HKEY hKey
, BOOL Deleted
, ULONG LineNumber
)
74 DWORD ErrorCode
= RegQueryInfoKeyW(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
76 ok_(__FILE__
, LineNumber
)(ErrorCode
== ERROR_KEY_DELETED
, "\n");
78 ok_(__FILE__
, LineNumber
)(ErrorCode
== ERROR_SUCCESS
, "\n");
80 #define ok_key_deleted(hKey) _test_key_deleted(hKey, TRUE, __LINE__)
81 #define ok_key_not_deleted(hKey) _test_key_deleted(hKey, FALSE, __LINE__)
83 static void _test_key_name(HKEY hKey
, PUNICODE_STRING Prefix
, LPCWSTR Name
, ULONG LineNumber
)
85 UNICODE_STRING ExpectedName
, KeyName
;
88 ExpectedName
.Length
= 0;
89 ExpectedName
.MaximumLength
= sizeof(Buffer
);
90 ExpectedName
.Buffer
= Buffer
;
92 RtlAppendUnicodeStringToString(&ExpectedName
, Prefix
);
93 RtlAppendUnicodeToString(&ExpectedName
, L
"\\");
94 RtlAppendUnicodeToString(&ExpectedName
, Name
);
96 GetKeyName(hKey
, &KeyName
);
98 ok_(__FILE__
, LineNumber
)(RtlCompareUnicodeString(&KeyName
, &ExpectedName
, TRUE
) == 0,
99 "Key name is %.*S, expected %.*S\n",
100 KeyName
.Length
, KeyName
.Buffer
,
101 ExpectedName
.Length
, ExpectedName
.Buffer
);
103 RtlFreeUnicodeString(&KeyName
);
106 #define ok_key_name(hKey, Prefix, Name) _test_key_name(hKey, Prefix, Name, __LINE__)
110 Test_CreateOpenKey(void)
112 HKEY MachineKey
, MachineSubKey
;
113 HKEY UserKey
, UserSubKey
;
114 HKEY ClassesRootKey
, ClassesRootSubKey
;
118 /* First create a subkey in HKLM */
119 ErrorCode
= RegCreateKeyExW(
121 L
"Software\\Classes\\Apitest_HKLM",
130 if (ErrorCode
== ERROR_ACCESS_DENIED
)
132 win_skip("Please run those tests with Administrator rights\n");
136 ok_dec(ErrorCode
, ERROR_SUCCESS
);
137 ok(!IS_HKCR(MachineKey
), "\n");
139 /* Open it in HKCR */
140 ErrorCode
= RegOpenKeyExW(
146 ok_dec(ErrorCode
, ERROR_SUCCESS
);
147 ok(IS_HKCR(ClassesRootKey
), "\n");
148 ok_key_name(ClassesRootKey
, &HKLM_ClassesPath
, L
"Apitest_HKLM");
150 /* Try opening it in HKCU */
151 UserKey
= (HKEY
)0xCAFEF00D;
152 ErrorCode
= RegOpenKeyExW(
154 L
"Software\\Classes\\Apitest_HKLM",
158 ok_dec(ErrorCode
, ERROR_FILE_NOT_FOUND
);
159 ok_hdl(UserKey
, NULL
);
162 RegCloseKey(ClassesRootKey
);
163 RegCloseKey(MachineKey
);
164 ErrorCode
= DeleteSubKey(HKEY_LOCAL_MACHINE
, L
"Software\\Classes", L
"Apitest_HKLM");
165 ok_dec(ErrorCode
, ERROR_SUCCESS
);
167 /* Try creating in HKCR */
168 ErrorCode
= RegCreateKeyExW(
178 ok_dec(ErrorCode
, ERROR_SUCCESS
);
179 ok(IS_HKCR(ClassesRootKey
), "\n");
180 ok_key_name(ClassesRootKey
, &HKLM_ClassesPath
, L
"Apitest_HKCR");
182 /* It should be present in HKLM */
183 ErrorCode
= RegOpenKeyExW(
185 L
"Software\\Classes\\Apitest_HKCR",
189 ok_dec(ErrorCode
, ERROR_SUCCESS
);
190 ok(!IS_HKCR(MachineKey
), "\n");
192 /* But not in HKCU */
193 UserKey
= (HKEY
)0xCAFEF00D;
194 ErrorCode
= RegOpenKeyExW(
196 L
"Software\\Classes\\Apitest_HKCR",
200 ok_dec(ErrorCode
, ERROR_FILE_NOT_FOUND
);
201 ok_hdl(UserKey
, NULL
);
203 /* This must delete the one in HKLM */
204 ErrorCode
= RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKCR");
205 ok_dec(ErrorCode
, ERROR_SUCCESS
);
206 ok_key_deleted(ClassesRootKey
);
207 ok_key_deleted(MachineKey
);
208 RegCloseKey(ClassesRootKey
);
209 RegCloseKey(MachineKey
);
211 /* Test that it is really not present anymore */
212 MachineKey
= (HKEY
)0xCAFEF00D;
213 ErrorCode
= RegOpenKeyExW(
215 L
"Software\\Classes\\Apitest_HKCR",
219 ok_dec(ErrorCode
, ERROR_FILE_NOT_FOUND
);
220 ok_hdl(MachineKey
, NULL
);
222 /* Try creating in HKCU */
223 ErrorCode
= RegCreateKeyExW(
225 L
"Software\\Classes\\Apitest_HKCU",
233 ok_dec(ErrorCode
, ERROR_SUCCESS
);
234 ok(!IS_HKCR(UserKey
), "\n");
236 /* Try opening it in HKCR */
237 ErrorCode
= RegOpenKeyExW(
243 ok_dec(ErrorCode
, ERROR_SUCCESS
);
244 ok(IS_HKCR(ClassesRootKey
), "\n");
245 ok_key_name(ClassesRootKey
, &HKCU_ClassesPath
, L
"Apitest_HKCU");
248 ErrorCode
= RegOpenKeyExW(
250 L
"Software\\Classes\\Apitest_HKCU",
254 ok_dec(ErrorCode
, ERROR_FILE_NOT_FOUND
);
255 ok_hdl(MachineKey
, NULL
);
257 ErrorCode
= RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKCU");
258 ok_dec(ErrorCode
, ERROR_SUCCESS
);
259 ok_key_deleted(ClassesRootKey
);
260 ok_key_deleted(UserKey
);
261 RegCloseKey(ClassesRootKey
);
262 RegCloseKey(UserKey
);
264 /* Test that it is really not present anymore */
265 UserKey
= (HKEY
)0xCAFEF00D;
266 ErrorCode
= RegOpenKeyExW(
268 L
"Software\\Classes\\Apitest_HKCU",
272 ok_dec(ErrorCode
, ERROR_FILE_NOT_FOUND
);
273 ok_hdl(UserKey
, NULL
);
275 /* Try creating in both HKLM and HKCU */
276 ErrorCode
= RegCreateKeyExW(
278 L
"Software\\Classes\\Apitest_HKLM_HKCU",
286 ok_dec(ErrorCode
, ERROR_SUCCESS
);
287 ok(!IS_HKCR(UserKey
), "\n");
289 ErrorCode
= RegCreateKeyExW(
291 L
"Software\\Classes\\Apitest_HKLM_HKCU",
299 ok_dec(ErrorCode
, ERROR_SUCCESS
);
300 ok(!IS_HKCR(MachineKey
), "\n");
302 /* Open it in HKCR */
303 ErrorCode
= RegOpenKeyExW(
305 L
"Apitest_HKLM_HKCU",
309 ok_dec(ErrorCode
, ERROR_SUCCESS
);
310 ok(IS_HKCR(ClassesRootKey
), "\n");
311 /* Verify it has opened the HKCU one */
312 ok_key_name(ClassesRootKey
, &HKCU_ClassesPath
, L
"Apitest_HKLM_HKCU");
314 /* Try the same thing, but this time with RegCreateKeyEx API */
315 RegCloseKey(ClassesRootKey
);
316 ErrorCode
= RegCreateKeyExW(
318 L
"Apitest_HKLM_HKCU",
326 ok_dec(ErrorCode
, ERROR_SUCCESS
);
327 ok(IS_HKCR(ClassesRootKey
), "\n");
328 /* Verify it has opened the HKCU one */
329 ok_key_name(ClassesRootKey
, &HKCU_ClassesPath
, L
"Apitest_HKLM_HKCU");
330 ok_hex(Disposition
, REG_OPENED_EXISTING_KEY
);
332 /* Deleting it from HKCR first deletes the one in HKCU */
333 ErrorCode
= RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKLM_HKCU");
334 ok_dec(ErrorCode
, ERROR_SUCCESS
);
335 ok_key_deleted(UserKey
);
336 ok_key_deleted(ClassesRootKey
);
337 ok_key_not_deleted(MachineKey
);
339 RegCloseKey(UserKey
);
340 RegCloseKey(ClassesRootKey
);
342 /* This deletes it from HKLM this time */
343 ErrorCode
= RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKLM_HKCU");
344 ok_dec(ErrorCode
, ERROR_SUCCESS
);
345 ok_key_deleted(MachineKey
);
346 RegCloseKey(MachineKey
);
348 /* See what happens with subkeys */
349 ErrorCode
= RegCreateKeyExW(
351 L
"Software\\Classes\\Apitest_HKLM",
359 ok_dec(ErrorCode
, ERROR_SUCCESS
);
360 ok(!IS_HKCR(MachineKey
), "\n");
362 /* Open it in HKCR */
363 ErrorCode
= RegOpenKeyExW(
369 ok_dec(ErrorCode
, ERROR_SUCCESS
);
370 ok(IS_HKCR(ClassesRootKey
), "\n");
371 ok_key_name(ClassesRootKey
, &HKLM_ClassesPath
, L
"Apitest_HKLM");
373 /* Create a corresponding subkey in HKCU */
374 ErrorCode
= RegCreateKeyExW(
376 L
"Software\\Classes\\Apitest_HKLM\\HKCU_Subkey",
384 ok_dec(ErrorCode
, ERROR_SUCCESS
);
385 ok(!IS_HKCR(UserSubKey
), "\n");
387 /* Open it as an HKCR subkey */
388 ErrorCode
= RegOpenKeyExW(
394 ok_dec(ErrorCode
, ERROR_SUCCESS
);
395 ok(IS_HKCR(ClassesRootSubKey
), "\n");
396 ok_key_name(ClassesRootSubKey
, &HKCU_ClassesPath
, L
"Apitest_HKLM\\HKCU_Subkey");
398 /* Try the same thing, but this time with RegCreateKeyEx API */
399 RegCloseKey(ClassesRootSubKey
);
400 ErrorCode
= RegCreateKeyExW(
410 ok_dec(ErrorCode
, ERROR_SUCCESS
);
411 ok(IS_HKCR(ClassesRootSubKey
), "\n");
412 /* Verify it has opened the HKCU one */
413 ok_key_name(ClassesRootSubKey
, &HKCU_ClassesPath
, L
"Apitest_HKLM\\HKCU_Subkey");
414 ok_hex(Disposition
, REG_OPENED_EXISTING_KEY
);
416 /* This one now exists */
417 ErrorCode
= RegOpenKeyExW(
419 L
"Software\\Classes\\Apitest_HKLM",
423 ok_dec(ErrorCode
, ERROR_SUCCESS
);
424 ok(!IS_HKCR(UserKey
), "\n");
427 ErrorCode
= RegDeleteKeyW(UserKey
, L
"HKCU_Subkey");
428 ok_dec(ErrorCode
, ERROR_SUCCESS
);
429 ok_key_deleted(UserSubKey
);
430 ok_key_deleted(ClassesRootSubKey
);
431 RegCloseKey(UserSubKey
);
432 RegCloseKey(ClassesRootSubKey
);
434 /* See what this deletes */
435 RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKLM");
436 ok_key_deleted(UserKey
);
437 RegCloseKey(UserKey
);
438 ok_key_not_deleted(ClassesRootKey
);
439 ok_key_not_deleted(MachineKey
);
442 RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKLM");
443 ok_key_deleted(ClassesRootKey
);
444 ok_key_deleted(MachineKey
);
445 RegCloseKey(ClassesRootKey
);
446 RegCloseKey(MachineKey
);
448 /* Same, but with HKCU first */
449 ErrorCode
= RegCreateKeyExW(
451 L
"Software\\Classes\\Apitest_HKCU",
459 ok_dec(ErrorCode
, ERROR_SUCCESS
);
460 ok(!IS_HKCR(UserKey
), "\n");
462 /* Open it in HKCR */
463 ErrorCode
= RegOpenKeyExW(
469 ok_dec(ErrorCode
, ERROR_SUCCESS
);
470 ok(IS_HKCR(ClassesRootKey
), "\n");
471 ok_key_name(ClassesRootKey
, &HKCU_ClassesPath
, L
"Apitest_HKCU");
473 /* Try creating a subkey with this HKCR handle, which points to a subkey in HKCU. */
474 ErrorCode
= RegCreateKeyExW(
484 ok_dec(ErrorCode
, ERROR_SUCCESS
);
485 ok(IS_HKCR(ClassesRootSubKey
), "\n");
486 /* It is in fact created in HKLM */
487 ok_key_name(ClassesRootSubKey
, &HKLM_ClassesPath
, L
"Apitest_HKCU\\HKCR_Subkey");
488 /* Let's see if we can delete it */
489 RegDeleteKeyW(ClassesRootKey
, L
"HKCR_Subkey");
490 ok_key_deleted(ClassesRootSubKey
);
491 RegCloseKey(ClassesRootSubKey
);
493 /* Create a corresponding subkey in HKLM */
494 ErrorCode
= RegCreateKeyExW(
496 L
"Software\\Classes\\Apitest_HKCU\\HKLM_Subkey",
504 ok_dec(ErrorCode
, ERROR_SUCCESS
);
505 ok(!IS_HKCR(MachineSubKey
), "\n");
507 /* Open it from the HKCR handle (which is still pointing to HKCU) */
508 ok_key_name(ClassesRootKey
, &HKCU_ClassesPath
, L
"Apitest_HKCU");
509 ErrorCode
= RegOpenKeyExW(
515 ok_dec(ErrorCode
, ERROR_SUCCESS
);
516 ok(IS_HKCR(ClassesRootSubKey
), "\n");
517 ok_key_name(ClassesRootSubKey
, &HKLM_ClassesPath
, L
"Apitest_HKCU\\HKLM_Subkey");
519 /* This one now exists */
520 ErrorCode
= RegOpenKeyExW(
522 L
"Software\\Classes\\Apitest_HKCU",
526 ok_dec(ErrorCode
, ERROR_SUCCESS
);
527 ok(!IS_HKCR(MachineKey
), "\n");
529 /* Delete this subkey */
530 ErrorCode
= RegDeleteKeyW(MachineKey
, L
"HKLM_Subkey");
531 ok_dec(ErrorCode
, ERROR_SUCCESS
);
532 ok_key_deleted(MachineSubKey
);
533 ok_key_deleted(ClassesRootSubKey
);
535 /* Create another subkey, this time from HKCU */
536 ErrorCode
= RegCreateKeyExW(
538 L
"Software\\Classes\\Apitest_HKCU\\HKCU_Subkey",
546 ok_dec(ErrorCode
, ERROR_SUCCESS
);
547 ok(!IS_HKCR(UserSubKey
), "\n");
549 /* And try creating it again as a subkey of this HKCR handle (which points to HKCU). */
550 ok_key_name(ClassesRootKey
, &HKCU_ClassesPath
, L
"Apitest_HKCU");
551 ErrorCode
= RegCreateKeyExW(
561 ok_dec(ErrorCode
, ERROR_SUCCESS
);
562 ok(IS_HKCR(ClassesRootSubKey
), "\n");
563 /* This time the one in HKCU is opened */
564 ok_key_name(ClassesRootSubKey
, &HKCU_ClassesPath
, L
"Apitest_HKCU\\HKCU_Subkey");
565 ok_hex(Disposition
, REG_OPENED_EXISTING_KEY
);
566 /* Let's see if we can delete it */
567 RegDeleteKeyW(ClassesRootKey
, L
"HKCU_Subkey");
568 ok_key_deleted(ClassesRootSubKey
);
569 RegCloseKey(ClassesRootSubKey
);
570 ok_key_deleted(UserSubKey
);
571 RegCloseKey(UserSubKey
);
573 RegCloseKey(MachineSubKey
);
574 RegCloseKey(ClassesRootSubKey
);
576 /* See what this deletes */
577 RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKCU");
578 ok_key_deleted(UserKey
);
579 RegCloseKey(UserKey
);
580 ok_key_deleted(ClassesRootKey
);
581 RegCloseKey(UserKey
);
582 ok_key_not_deleted(MachineKey
);
585 RegDeleteKeyW(HKEY_CLASSES_ROOT
, L
"Apitest_HKCU");
586 ok_key_deleted(MachineKey
);
587 RegCloseKey(MachineKey
);
592 Test_DuplicateHandle(void)
594 HKEY KeyHandle
, DupHandle
;
598 ErrorCode
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"CLSID", 0, KEY_READ
, &KeyHandle
);
599 ok_dec(ErrorCode
, ERROR_SUCCESS
);
600 ok(IS_HKCR(KeyHandle
), "\n");
602 Duplicated
= DuplicateHandle(GetCurrentProcess(), KeyHandle
, GetCurrentProcess(), (PHANDLE
)&DupHandle
, 0, 0, DUPLICATE_SAME_ACCESS
);
603 ok(Duplicated
, "\n");
604 ok(DupHandle
!= NULL
, "\n");
605 ok(!IS_HKCR(DupHandle
), "\n");
607 RegCloseKey(KeyHandle
);
608 RegCloseKey(DupHandle
);
611 START_TEST(HKEY_CLASSES_ROOT
)
616 /* Get HKCU real key name */
617 ErrorCode
= RegOpenKeyExW(
619 L
"Software\\Classes",
623 ok_dec(ErrorCode
, ERROR_SUCCESS
);
624 GetKeyName(UserKey
, &HKCU_ClassesPath
);
625 RegCloseKey(UserKey
);
627 Test_CreateOpenKey();
628 Test_DuplicateHandle();