UniDAC

64-bit Development with Embarcadero RAD Studio XE2

RAD Studio XE2 Overview

RAD Studio XE2 is the major breakthrough in the line of all Delphi versions of this product. It allows deploying your applications both on Windows and Mac OS platforms. Additionally, it is now possible to create 64-bit Windows applications to fully benefit from the power of new hardware. Moreover, you can create visually spectacular applications with the help of the FireMonkey GPU application platform.

Its main features are the following:

Changes in 64-bit Application Development

64-bit platform support implies several important changes that each developer must keep in mind prior to the development of a new application or the modernization of an old one.

General

RAD Studio XE2 IDE is a 32-bit application. It means that it cannot load 64-bit packages at design-time. So, all design-time packages in RAD Studio XE2 IDE are 32-bit.

Therefore, if you develop your own components, you should remember that for the purpose of developing components with the 64-bit platform support, you have to compile run-time packages both for the 32- and 64-bit platforms, while design-time packages need to be compiled only for the 32-bit platform. This might be a source of difficulties if your package is simultaneously both a run-time and a design-time package, as it is more than likely that this package won't be compiled for the 64-bit platform. In this case, you will have to separate your package into two packages, one of which will be used as run-time only, and the other as design-time only.

For the same reason, if your design-time packages require that certain DLLs be loaded, you should remember that design-time packages can be only 32-bit and that is why they can load only 32-bit versions of these DLLs, while at run-time 64-bit versions of the DLLs will be loaded. Correspondingly, if there are only 64-bit versions of the DLL on your computer, you won't be able to use all functions at design-time and, vice versa, if you have only 32-bit versions of the DLLs, your application won't be able to work at run-time.

Extended type

For this type in a 64-bit applications compiler generates SSE2 instructions instead of FPU, and that greatly improves performance in applications that use this type a lot (where data accuracy is needed). For this purpose, the size and precision of Extended type is reduced:

TYPE 32-bit 64-bit
Extended 10 bytes 8 bytes

The following two additional types are introduced to ensure compatibility in the process of developing 32- and 64-bit applications:

Extended80 – whose size in 32-bit application is 10 bytes; however, this type provides the same precision as its 8-byte equivalent in 64-bit applications.

Extended80Rec – can be used to perform low-level operations on an extended precision floating-point value. For example, the sign, the exponent, and the mantissa can be changed separately. It enables you to perform memory-related operations with 10-bit floating-point variables, but not extended-precision arithmetic operations.

Pointer and Integers

The major difference between 32- and 64-bit platforms is the volume of the used memory and, correspondingly, the size of the pointer that is used to address large memory volumes.

TYPE 32-bit 64-bit
Pointer 4 bytes 8 bytes

At the same time, the size of the Integer type remains the same for both platforms:

TYPE 32-bit 64-bit
Integer 4 bytes 4 bytes

That is why, the following code will work incorrectly on the 64-bit platform:

Ptr := Pointer(Integer(Ptr) + Offset);

While this code will correctly on the 64-bit platform and incorrectly on the 32-bit platform:

Ptr := Pointer(Int64(Ptr) + Offset);

For this purpose, the following platform-dependent integer type is introduced:

TYPE 32-bit 64-bit
NativeInt 4 bytes 8 bytes
NativeUInt 4 bytes 8 bytes

This type helps ensure that pointers work correctly both for the 32- and 64-bit platforms:

Ptr := Pointer(NativeInt(Ptr) + Offset);

However, you need to be extra-careful when developing applications for several versions of Delphi, in which case you should remember that in the previous versions of Delphi the NativeInt type had different sizes:

TYPE Delphi Version Size
NativeInt D5 N/A
NativeInt D6 N/A
NativeInt D7 8 bytes
NativeInt D2005 8 bytes
NativeInt D2006 8 bytes
NativeInt D2007 8 bytes
NativeInt D2009 4 bytes
NativeInt D2010 4 bytes
NativeInt Delphi XE 4 bytes
NativeInt Delphi XE2 4 or 8 bytes

Out parameters

Some WinAPIs have OUT parameters of the SIZE_T type, which is equivalent to NativeInt in Delphi XE2. The problem is that if you are developing only a 32-bit application, you won't be able to pass Integer to OUT, while in a 64-bit application, you will not be able to pass Int64; in both cases you will have to pass NativeInt.

For example:

procedure MyProc(out Value: NativeInt);
begin
  Value := 12345;
end; 

var
    Value1: NativeInt;
{$IFDEF WIN32}
  Value2: Integer;
{$ENDIF}
{$IFDEF WIN64}
  Value2: Int64;
{$ENDIF}
begin
   MyProc(Value1); // will be compiled;

 MyProc(Value2); // will not be compiled !!!
end;

Win API

If you pass pointers to SendMessage/PostMessage/TControl.Perform, the wParam and lParam parameters should be type-casted to the WPARAM/LPARAM type and not to Integer/Longint.

Correct:

SendMessage(hWnd, WM_SETTEXT, 0, LPARAM(@MyCharArray));

Wrong:

SendMessage(hWnd, WM_SETTEXT, 0, Integer(@MyCharArray));

Replace SetWindowLong/GetWindowLog with SetWindowLongPtr/GetWindowLongPtr for GWLP_HINSTANCE, GWLP_ID, GWLP_USERDATA, GWLP_HWNDPARENT and GWLP_WNDPROC as they return pointers and handles. Pointers that are passed to SetWindowLongPtr should be type-casted to LONG_PTR and not to Integer/Longint.

Correct:

SetWindowLongPtr(hWnd, GWLP_WNDPROC, LONG_PTR(@MyWindowProc)); 

Wrong:

SetWindowLong(hWnd, GWL_WNDPROC, Longint(@MyWindowProc)); 

Pointers that are assigned to the TMessage.Result field should use a type-cast to LRESULT instead of Integer/Longint.

Correct:

Message.Result := LRESULT(Self);

Wrong:

Message.Result := Integer(Self);

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)

Assembler

In order to make your application (that uses assembly code) work, you will have to make several changes to it:

You can use conditional defines to make your application work with different architectures.

You can learn more about Assembly code here: http://docwiki.embarcadero.com/RADStudio/en/Using_Inline_Assembly_Code You can also look at the following article that will help you to make your application support the 64-bit platform: http://docwiki.embarcadero.com/RADStudio/en/Converting_32-bit_Delphi_Applications_to_64-bit_Windows

Exception handling

The biggest difference in exception handling between Delphi 32 and 64-bit is that in Delphi XE2 64-bit you will gain more performance because of different internal exception mechanism. For 32-bit applications, the Delphi compiler (dcc32.exe) generates additional code that is executed any way and that causes performance loss. The 64-bit compiler (dcc64.exe) doesn't generate such code, it generates metadata and stores it in the PDATA section of an executable file instead.

But in Delphi XE2 64-bit it's impossible to have more than 16 levels of nested exceptions. Having more than 16 levels of nested exceptions will cause a Run Time error.

Debugging

Debugging of 64-bit applications in RAD Studio XE2 is remote. It is caused by the same reason: RAD Studio XE2 IDE is a 32 application, but your application is 64-bit. If you are trying to debug your application and you cannot do it, you should check that the Include remote debug symbols project option is enabled.

To enable it, perform the following steps:

  1. Open Project Options (in the main menu Project->Options).
  2. In the Target combobox, select Debug configuration - 64-bit Windows platform. If there is no such option in the combobox, right click "Target Platforms" in Project Manager and select Add platform. After adding the 64-bit Windows platform, the Debug configuration - 64-bit Windows platform option will be available in the Target combobox.
  3. Select Linking in the left part of the Project Options form.
  4. enable the Include remote debug symbols option.

After that, you can run and debug your 64-bit application.

To enable remote debugging, perform the following steps:

  1. Install Platform Assistant Server (PAServer) on a remote computer. You can find PAServer in the %RAD_Studio_XE2_Install_Directory%\PAServer directory. The setup_paserver.exe file is an installation file for Windows, and the setup_paserver.zip file is an istallation file for MacOS.
  2. Run the PAServer.exe file on a remote computer and set the password that will be used to connect to this computer.
  3. On a local computer with RAD Studio XE2 installed, right-click the target platform that you want to debug in Project Manager and select Assign Remote Profile. Click the Add button in the displayed window, input your profile name, click the Next button, input the name of a remote computer and the password to it (that you assigned when you started PAServer on a remote computer).

After that, you can test the connection by clicking the Test Connection button. If your connection failed, check that your firewalls on both remote and local computers do not block your connection, and try to establish a connection once more. If your connection succeeded, click the Next button and then the Finish button. Select your newly created profile and click OK.

After performing these steps you will be able to debug your application on a remote computer. You application will be executed on a remote computer, but you will be able to debug it on your local computer with RAD Studio XE2.

For more information about working with Platform Assistant Server, please refer to http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Running_the_Platform_Assistant_on_Windows

© 1997-2024 Devart. All Rights Reserved. Request Support DAC Forum Provide Feedback