When you want to build native Windows applications, Delphi is still a major tour de force in the world of development tools. But currently it can only generate 32-bit executables and so cannot take advantage of all the memory space available when running 64-bit versions of Windows. That will be changing very soon.
Earlier this month David Intersimone posted a 13.5 minute video showing how the pre-release 64-bit Delphi compiler is coming along - you can see it here.
Summary from the video is that most regular Delphi code will simply compile and run. The Delphi RTL (run-time library) and VCL (Visual Component Library) have been updated and reworked internally where appropriate to just work in 64-bit Windows without undue changes to their interface, in much the same way as occurred with Delphi 2 with the move from 16-bit to 32-bit.
Of course things aren’t as simple as that, and there are some key areas where attention must be paid to have smooth transition and have code work in 64-bit but most regular Delphi code will pass through untouched.
In order to get prepared for 64-bit Delphi (or Delphi/64) and to assess your code for areas where attention needs to be paid the slides in the video point out some key gotchas, which I’m listing here to make them easily locatable (much easier to find text on a web page than in a video):
Things that stay the same:
Shortint
andByte
are still 8 bits.
Smallint
andWord
are still 16 bits.
Integer
,Longint
,Cardinal
andLongWord
are still 32 bits.
Int64
andUInt64
are still 64 bits.
UnicodeString
,AnsiString
,WideString
.
- The Delphi exception system.
- The RTL (Run-Time Library), e.g. SysUtils, Classes, generics.Collections etc.
- The VCL (Visual Component Library), e.g. Forms, Graphics, Controls, menus, etc.
- Windows API
Things that are different:
NativeInt
andNativeUint
are now 64 bits, not 32.
Pointer
and all pointer types are now 64 bits, not 32. That covers things such asString
,AnsiString
,WideString
,UnicodeString
, class instance, class reference, interface reference, procedure pointer, dynamic array,PAnsiChar
,PWideChar
,PChar
. Remember that string variables are really pointers to reference-counted string data.
- Dynamic arrays now use 64-bit indexing, not 32-bit.
- Floating point math is done with type
Double
(the 64-bit float type) – 32-bit floating point math not supported (Single
will map toDouble
).
Things to bear in mind:
- The
Tag
property will beNativeInt
, meaning you can still cast object instances and other pointers and store them inTag
at runtime. Note thatTag
was originally added to allow unique identification of components which share events. Think:case (Sender as TComponent).Tag of ...
SizeOf(Pointer) <> SizeOf(Integer)
Integer
↔Pointer
casts will break in 64-bit
SizeOf(THandle) = SizeOf(Pointer)
- All handles (
HWND
,HDC
, etc.) are pointer-sized, i.e. they will be 64-bit in the 64-bit compiler
- All code in the process must be 64-bit, including all dependent DLLs
- There is only one calling convention (
register
,pascal
,cdecl
,stdcall
will be ignored), althoughsafecall
is still handled as a special case
- Old “pointer math” may break
- This will work in 32-bit and 64-bit:
MyPtr := PByte(P) + 10
- This will work in 32-bit and 64-bit:
- Inline assembly
- Only procedural level
asm
blocks are supported –asm
blocks cannot be mixed with Pascal code
- Stack must be 16-byte aligned at each call instruction
- Define locals for temporary storage
- Do not modify the RSP stack pointer
- In the new unified calling convention the first 4 parameters are passed in registers: RCX, RDX, R8 & R9 (or XMM0-XMM3)
- Only procedural level
- Exception unwinding
- Pure Delphi code works as before
- Inline assembly can cause exception unwinding to fail if not properly written
- Pure Delphi code works as before
- Windows API gotchas
SetWindowLong
/GetWindowLong
should be replaced withSetWindowLongPtr
/GetWindowLongPtr
forGWLP_HINSTANCE
,GWLP_WNDPROC
etc, because they return pointers and handles- Pointers passed to
SetWindowLongPtr
should cast toLONG_PTR
rather than toInteger
/Longint
- Pointers passed to
SetWindowLong
is mapped toSetWindowLongPtr
in Windows.pas- calls to this mapped version are safe so long as they are cast correctly
- Use explicit casts to
WPARAM
/LPARAM
where appropriate- E.g. passing pointers through SendMessage:
SendMessage(hWnd, WM_SETTEXT, 0, LPARAM(@MyCharArray));
- E.g. passing pointers through SendMessage:
- Use
LRESULT
to cast message results- E.g.
Message.Result := LRESULT(Self)
- E.g.
- Message cracker record definitions (
TWMxxx
) have changed to accommodate altered alignment and field sizes
Things to do to your code today:
- Find all
Integer
↔Pointer
casts (includingInteger
↔ instance casts)
- Check for
Pointer
size assumptions
- Ensure external dependencies are available in 64-bit
- Image/bitmap libraries
- Hardware interface libraries
- ActiveX controls
- Image/bitmap libraries
- Consider rewriting assembler code in pure Pascal
- This offers better portability (think future ARM CPU support)
- Rely more on algorithmic performance rather than raw assembly performance
- This offers better portability (think future ARM CPU support)
To get a heads-up on some of the issues surrounding 64-bit programming on Windows you read:
- Everything You Need To Know To Start Programming 64-Bit Windows Systems by Matt Pietrek
- x64 Software Conventions in the Visual Studio 2010 documentation
Finally, if you are a Delphi XE user you get priority access to the Delphi 64-bit beta. Non-XE users can also get on the beta, but there will be limited places, and XE users will be given priority. More information about the beta program is available here.
Also, 80-bit floating point calculatin (Extended type) will be gone in 64-bit.
ReplyDeleteGood point, Primoz.
ReplyDeleteI'll assume Extended will also map onto Double.
That's how I understood DavidI, yes.
ReplyDelete