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