When I compile the following code in Delphi XE2 for the target platform 64-bit Windows ...
function HKeyToString(_HKey: HKey): string;
begin
case _HKey of
HKEY_CLASSES_ROOT: result := 'HKEY_CLASSES_ROOT'; // do not translate
HKEY_CURRENT_USER: result := 'HKEY_CURRENT_USER'; // do not translate
HKEY_LOCAL_MACHINE: result := 'HKEY_LOCAL_MACHINE'; // do not translate
HKEY_USERS: result := 'HKEY_USERS'; // do not translate
HKEY_PERFORMANCE_DATA: result := 'HKEY_PERFORMANCE_DATA'; // do not translate
HKEY_CURRENT_CONFIG: result := 'HKEY_CURRENT_CONFIG'; // do not translate
HKEY_DYN_DATA: result := 'HKEY_DYN_DATA'; // do not translate
else
Result := Format(_('unknown Registry Root Key %x'), [_HKey]);
end;
end;
... I get warnings for each of the HKEY_-Constants: "W1012 Constant expression violates subrange bounds"
I checked the declarations in Winapi.Windows (with Ctrl+Leftclick on the identifiers):
type
HKEY = type UINT_PTR;
{...}
const
HKEY_CLASSES_ROOT = HKEY(Integer($80000000));
These look fine to me. Why does the compiler still think there is a problem?
On the 64 bit compiler the actual value of HKEY_CLASSES_ROOT
is:
FFFFFFFF80000000
That's because the cast to Integer
makes 80000000
into a negative number. And then the conversion to unsigned leads to FFFFFFFF80000000
. Note that this value is correct. The declaration in the windows header file is:
#define HKEY_CLASSES_ROOT (( HKEY ) (ULONG_PTR)((LONG)0x80000000) )
and when you include the header file and inspect the value of HKEY_CLASSES_ROOT
in a C++ program, it is the exact same value as for the Delphi declaration.
And then we can solve the puzzle from the Delphi documentation which states that the selectors in a case statement can only be:
any expression of an ordinal type smaller than 32 bits
You have no choice but to replace your case
statement with an if
statement.
HKEY=UINT_PTR
is an unsigned 64 bit integer in your case, and case ... of
statement seems not to handle it.
The XE2/XE3 compiler front-end still assumes it targets a 32bit platform, even if there is no technical reason for the compiler back-end not able to handle 64 bit case statements (with the classic sub register,constant; jz @...
asm code generation pattern).
You can try to typecast everything to integer
:
const
HKEY_CLASSES_ROOT32 = Integer($80000000);
...
function HKeyToString(_HKey: integer): string;
begin
case _HKey of
HKEY_CLASSES_ROOT32: result := 'HKEY_CLASSES_ROOT'; // do not translate
...
or just ignore the upmost 32 bits of the _HKey value (this is the same):
function HKeyToString(_HKey: HKey): string;
begin
case _HKey and $ffffffff of
HKEY_CLASSES_ROOT and $ffffffff: result := 'HKEY_CLASSES_ROOT'; // do not translate
...
It will work as expected under Windows: due to the limited number of HKEY_*
constants, I think you can just ignore the upmost 32 bits of the _HKey
value, and therefore use the buggy case .. of...
statement. And it will work of course for both Win32 and Win64.
I suspect even ... and $f
will be enough - see all HKEY_*
constants.
Last (and certainly best solution) is to use good old nested if... else if...
statements:
function HKeyToString(_HKey: HKey): string;
begin
if_HKey=HKEY_CLASSES_ROOT then
result := 'HKEY_CLASSES_ROOT' else // do not translate
if_HKey=HKEY_CURRENT_USER then
result := 'HKEY_CURRENT_USER' else // do not translate
....
I guess the last one is preferred, and not slower, with modern pipelines CPUs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With