Converting 32-bit Delphi Applications to 64-bit Windows
Go Up to 64-bit Windows Application Development
If you have a code base of 32-bit Windows Delphi applications that you want to convert to 64-bit Windows, you should
- Open your 32-bit application in the IDE, add and activate the 64-bit Windows target platform, and compile your application as a 64-bit Windows application. (For details, see Steps in Creating Multi-Device Applications.)
- Review and handle the following issues (mostly related to pointer operations, NativeInt size, and Assembly code).
Contents
Pointer operations
You should review pointer operations in your code base.
- The size of all pointers has changed, as follows:
- On the 32-bit Windows platform, a pointer is 4 bytes.
- On the 64-bit Windows platform, a pointer is 8 bytes.
- You cannot assume that:
SizeOf(Pointer)=SizeOf(Integer/Cardinal/Longint)
- If you increment pointers, be aware that the behavior of a 64-bit pointer might not be the same as the behavior of a 32-bit pointer. You might need to make adjustments in your code.
- Correct:
MyPtr := PByte(P) + 10;
- Backward-compatible:
MyPtr := PAnsiChar(P) + 10;
- Wrong:
MyPtr := Pointer(Integer(P) + 10);
- You cannot assume that:
SizeOf(Pointer) == 4
- Correct:
Move(FSelection[Index + 1], FSelection[Index], (FSelectionCount - Index - 1) * SizeOf(Pointer));
- Wrong:
Move(FSelection[Index + 1], FSelection[Index], (FSelectionCount - Index - 1) * 4);
For more information about using pointers in a 64-bit Windows applications, see the MSDN article, Rules for Using Pointers.
Integer Types
- On the 64-bit Windows platform, integer remains 4 bytes.
Size of NativeInt
Changes
- On the 64-bit Windows platform, the
NativeInt
size is now 8 bytes. - On the 32-bit Windows platform, the
NativeInt
size is still 4 bytes.
Inline Assembly code
If your application contains inline assembly (ASM) code, you need to examine the ASM code and make the following changes:
- Mixing of assembly statements with Pascal code is not supported in 64-bit applications. Replace assembly statements with either Pascal code or functions written completely in assembly.
- Porting assembly code from IA-32 to Intel 64 cannot be done by simply copying the code. Consider the architecture specifics, such as the size of pointers and aligning. You may also want to consult the processor manual for new instructions. If you want to compile the same code for different architectures, use conditional defines. See Using Conditional Defines for Cross-Platform Code in "Using Inline Assembly Code."
RAD Studio supports Intel x86 through SSE4.2 and AMD 3dNow, and for x64, Intel/AMD through SSE4.2.
For more information, see:
Winapi Issues
- If you pass pointers to
SendMessage/PostMessage/TControl.Perform
, thewParam
andlParam
parameters should be type-casted to theWPARAM/LPARAM
type and not toInteger/Longint
.- Correct:
SendMessage(hWnd, WM_SETTEXT, 0, LPARAM(@MyCharArray));
- Wrong:
SendMessage(hWnd, WM_SETTEXT, 0, Integer(@MyCharArray));
- Correct:
- Replace
SetWindowLong/GetWindowLog
withSetWindowLongPtr/GetWindowLongPtr
forGWLP_HINSTANCE
,GWLP_ID
,GWLP_USERDATA
,GWLP_HWNDPARENT
andGWLP_WNDPROC
as they return pointers and handles. Pointers that are passed toSetWindowLongPtr
should be type-casted toLONG_PTR
and not toInteger/Longint
.- Correct:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, LONG_PTR(@MyWindowProc));
- Wrong:
SetWindowLong(hWnd, GWL_WNDPROC, Longint(@MyWindowProc));
- Correct:
- Pointers that are assigned to the
TMessage.Result
field should use a type-cast toLRESULT
instead ofInteger/Longint
.- Correct:
Message.Result := LRESULT(Self);
- Wrong:
Message.Result := Integer(Self);
- Correct:
- All
TWM...
-records for the windows message handlers must use the correct Windows types for the fields:Msg: UINT; wParam: WPARAM; lParam: LPARAM; Result: LRESULT)
Record Type Data Field Alignment
In previous versions of Delphi, packed records were used to ensure proper data alignment when calling external libraries and notably certain external Windows API functions that require record or struct parameters. Unused data fields were introduced to "pad things out" and make the needed data fields line up as needed. The current compiler implementation eliminates the need for using packed records this way, in most cases. Revising your existing source code to eliminate needless packed records and "padding" makes the source more clear and easier to maintain.
If you require that your existing data files maintain compatibility with older versions of Delphi, apply the compiler directive {$OLDTYPELAYOUT ON} to source code where the older record organization is still needed.
Other Minor Issues to Resolve
- The DataEvent procedure in the VCL-RTL is affected by the change in size of
NativeInt
.
- You might see a compiler override error on virtual methods (E2170 Cannot override a non-virtual method). Code changes are required in this case.
- Run-time function patching, like injecting an unconditional jump instruction to redirect a function, has to be rewritten as 64-bit instructions.
- 64-bit External .obj Files: If you expect your 64-bit Windows application to link to an external .obj file, keep in mind that you will need a 64-bit version of the .obj file to link with a 64-bit Windows application.