Devart Blog

64-bit Development with Delphi XE2

Posted by on September 28th, 2011

Delphi XE2

Delphi XE2 Overview

Delphi 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:

  • Windows 64-bit platform support;
  • Mac OS support;
  • FireMonkey application development platform;
  • Live data bindings with visual components;
  • VCL styles for Windows applications.

For more information about Delphi XE2, please refer to Delphi XE2 Overview article on Embarcadero website.

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

Delphi 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 Delphi 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 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 applications that are compiled for the 64-bit platform 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 the 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 works incorrectly on the 64-bit platform:

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

While this code works 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 WinAPI functions 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 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;

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);

Assembler

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

  • rewrite your code that mixes Pascal code and assembly code. Mixing them is not supported in 64-bit applications;
  • rewrite assembly code that doesn’t consider architecture and processor specifics.

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

You can learn more about Assembly code here. You can also look at the following article that will help you to make your application support the 64-bit platform.

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 Delphi XE2 is remote. It is caused by the same reason: Delphi 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.
    Select 64-bit 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.
Adding platform

  • Select Linking in the left part of the Project Options form.
  • Enable the Include remote debug symbols option.
    Project options

 

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 Delphi XE2 installed, right-click the target platform that you want to debug in Project Manager and select Assign Remote Profile.
    Assigning remote profile
  4. Click the Add button in the displayed window and input your profile name.Creating remote profile
  5. 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).Creating remote profile 2
  6. 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.
    Profile is added

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 Delphi XE2.

For more information about working with Platform Assistant Server, please refer to this article.

Database-Specific Aspects of 64-bit Development

For each database, the specifics of the 64-bit development is mainly conditioned by the use of particular database client libraries. When our connectivity solutions are used in Direct mode (without involving database client software), the specifics of developing applications depends exclusively on peculiarities of 64-bit platform regardless of the used database.

For example, our PostgreSQL connectivity solutions (PgDAC, UniDAC and dbExpress Driver for PostgreSQL) work with the PostgreSQL database directly. Our connectivity solutions for Oracle and MySQL can be used in Direct mode as well as with the corresponding database client.

For our connectivity solutions, using DBMS client libraries, the following requiements should be met. As Delphi XE2 is a 32-bit application, it can load only 32-bit libraries. So, to connect to the database at design-time, you need to use 32-bit client library, while at run-time you will need the 64-bit client library. For SQL Server, InterBase and Firebird, MySQL (in client mode), and SQLite you need to place the 32-bit client library to the C:WindowsSysWOW64 directory (if you need to connect to the database at design-time), and the 64-bit client library, used for connecting to the database at run-time, to the C:WindowsSystem32 directory. Note that developers of SQLite do not provide a ready driver for x64 platforms, and for x64 applications you need to manually compile the sqlite library (for example, in MS VisualStudio).

Our connectivity solutions for Oracle (ODAC, UniDAC, dbExpress driver for Oracle) use the DEFAULT Oracle Client as standard, so depending on the capacity of the DEFAULT Oracle Client you need to explicitly specify either the 64-bit client for run-time (if the DEFAULT Oracle Client is 32-bit), or the 32-bit client for design-time (if the DEFAULT Oracle Client is 64-bit), or you may explicitly specify both clients – for run-time and for design-time.

When developing cross-platform application using UniDAC to work with the MS Access database, you should remember that it is impossible to install two (32- and 64-bit) drivers on the same system (Microsoft limitation). That is why, if you need to connect to the database at design-time, the 32-bit driver must be installed on the development computer, since Delphi XE2 uses x32 libraries at design-time. If no such connection is needed, you can install the x64 MS Access driver. All the other aspects of x64 and x32 development are identical.

As regards using UniDAC for connecting to other database servers through ODBC, for information on drivers for different platforms and specifics contact their developers.

4 Responses to “64-bit Development with Delphi XE2”

  1. Carroll Yoney Says:

    I really appreciate this your good article from there i get something that i want to know thanks for this usefull informations

  2. runsheng Says:

    This article is very good and usefull,thank you!

  3. Alfredo Says:

    Hey I am so excited I found your weblog, I really found you by error, while I was browsing
    on Digg for something else, Regardless I am here now and would just like to say many thanks for a fantastic post and a all round thrilling blog (I also love the
    theme/design), I don’t have time to look over it all at the minute but I have bookmarked it and also added your RSS feeds, so when I have time I will be back to read more, Please do keep up the excellent job.

  4. AndreyP Says:

    Thank you for your kind words, Alfredo. We highly appreciate your interest.

Leave a Reply