Subject: | Incorrect 64-bit HKEY_* constants |
Date: | Sat, 14 Nov 2015 16:21:42 -0500 |
To: | bug-Win32API-Registry [...] rt.cpan.org |
From: | Richard Burkert <richard.burkert [...] gmail.com> |
I'd like to point out that the values for the Win32API::Registry::HKEY_*
constants are technically incorrect for 64-bit Perl builds, despite working
in practice for the most part. The Windows SDK defines the HKEY values for
the predefined keys by first casting an original literal value (>=
0x80000000) to LONG (signed 32-bit), then to ULONG_PTR (unsigned 32- or
64-bit, depending on architecture), then to HKEY, such as in the
following macro definition for HKEY_CLASSES_ROOT in winreg.h:
#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000))
For 32-bit builds this results in the final HKEY value being identical to
the original literal value, but for 64-bit builds, because of the
intermediate signed LONG cast which is then cast to the larger unsigned
ULONG_PTR type, the original value is effectively sign-extended to 64-bits,
resulting in the most significant 32 bits being set. So in 64-bit
architectures HKEY_CLASSES_ROOT is 0xFFFFFFFF80000000, HKEY_CURRENT_USER is
0xFFFFFFFF80000001, and so on.
It seems that most of the Windows Reg* API functions (perhaps all of the
ones exposed by Win32API::Registry) compensate for being passed 32-bit
versions of those predefined key handles, which apparently is why
Win32API::Registry isn't completely broken on 64-bit Perl builds. I only
noticed the problem when trying to pass the Win32API::Registry::HKEY_*
values to RegOverridePredefKey (used via Win32::API), which seems to be an
exception and fails with error code 6 (ERROR_INVALID_HANDLE) when passed
32-bit versions of those handles.
Tested using Win32API::Registry 0.33 on strawberry 5.20.3.1-64bit on Win7
Pro x64