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:
ShortintandByteare still 8 bits.
SmallintandWordare still 16 bits.
Integer,Longint,CardinalandLongWordare still 32 bits.
Int64andUInt64are 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:
NativeIntandNativeUintare now 64 bits, not 32.
Pointerand 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 (Singlewill map toDouble).
Things to bear in mind:
- The
Tagproperty will beNativeInt, meaning you can still cast object instances and other pointers and store them inTagat runtime. Note thatTagwas originally added to allow unique identification of components which share events. Think:case (Sender as TComponent).Tag of ...
SizeOf(Pointer) <> SizeOf(Integer)Integer↔Pointercasts 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,stdcallwill be ignored), althoughsafecallis 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
asmblocks are supported –asmblocks 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/GetWindowLongshould be replaced withSetWindowLongPtr/GetWindowLongPtrforGWLP_HINSTANCE,GWLP_WNDPROCetc, because they return pointers and handles- Pointers passed to
SetWindowLongPtrshould cast toLONG_PTRrather than toInteger/Longint
- Pointers passed to
SetWindowLongis mapped toSetWindowLongPtrin Windows.pas- calls to this mapped version are safe so long as they are cast correctly
- Use explicit casts to
WPARAM/LPARAMwhere appropriate- E.g. passing pointers through SendMessage:
SendMessage(hWnd, WM_SETTEXT, 0, LPARAM(@MyCharArray));
- E.g. passing pointers through SendMessage:
- Use
LRESULTto 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↔Pointercasts (includingInteger↔ instance casts)
- Check for
Pointersize 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