Delphi XE2 FireMonkey Applications Deployment on Mac OS X

February 2nd, 2012

RAD Studio XE2 allows creating applications for Mac OS X. But the problem is that RAD Studio XE2 (both Delphi XE2 and C++Builder XE2) can be installed and run only under MS Windows, therefore applications for Mac OS X can be developed under MS Windows. That is why many people may face the problem of deploying applications on Mac OS X. Taking this into account, we decided to write this article that will help our users deal with deploying problem and deploy their applications to Mac OS X successfully. In this article, we will tell about two ways of applications deploying on Mac OS X and the peculiarities that must be taken into account during deploying applications that use Devart Data Access Components and Devart dbExpress drivers.

Using PAServer

The easiest way to deploy applications to Mac OS X is to deploy them using PAServer.

When PAServer is used to debug applications on a remote computer with Mac OS X, it copies executable Mac OS X application packages to the “PAServer_Installation_Directory” directory (where “PAServer_Installation_Directory” is the “/Users/$USER/Applications/Embarcadero/PAServer” directory by default). In the scratch-dir directory PAServer creates directories with names, that consist of the computer name and the remote profile name. For example, if the computer name (where RAD Studio XE2 is run) is “MyPC”, and the remote profile name for the Mac OS X platform is “Mac OS X”, PAServer will create the “PAServer_Installation_Directory/scratch-dir/MyPC-Mac OS X” directory. In this directory, PAServer will create an application package with the name of the project plus the “.app” extension. For example, if your application name is “MyProject”, PAServer will create the “MyProject.app” application package.

You can use PAServer for both debugging your application and for deploying it as well. For this, you should choose Release Build Configuration and run it without debugging (the Run Without Debugging command from the Run menu). Also, before the final deployment, you should clean the application package folder (for example, “MyProject.app”) from all old files that could remain after previous runnings and deployments.

Note: You can choose files to deploy in an application package by selecting “Deployment” from the Project menu in RAD Studio XE2.

Manual

An application package is internally represented by a folder with the following structure:

For Delphi:
For C++Builder:

Note: To view the content of the application package in Mac OS X, you can right click on package and select “Show Package Contents” from the shortcut menu.

All needed files to create the Mac OS X application package are supplied by RAD Studio XE2. To create the Mac OS X application package manually, the following steps must be performed:

  • create a FireMonkey Delphi or C++Builder application;
  • add the OS X platform to Target Platforms and make it active;
  • build the application using Release Build Configuration;
  • create a folder with the name that consists of the project name and the “.app” extension, for example, “MyProject.app”;
  • create the Contents folder in the MyProject.app folder;
  • copy the “MyProject_Directory\OSX32\Release\MyProject.info.plist” file to the Contents folder and rename it to info.plist;
  • create the MacOS folder in the Contents folder;
  • for Delphi applications: copy
    “RAD_Studio_XE2_Install_Directory\Redist\osx32\libcgunwind.1.0.dylib”
    to the MacOS folder;
    for C++Builder applications: copy
    “RAD_Studio_XE2_Install_Directory\Redist\osx32\libcgunwind.1.0.dylib”,
    “RAD_Studio_XE2_Install_Directory\Redist\osx32\libcgcrtl.dylib” and
    “RAD_Studio_XE2_Install_Directory\Redist\osx32\libcgstl.dylib”
    to the MacOS folder;
  • copy the “MyProject_Directory\OSX32\Release\MyProject” file to the MacOS folder;
  • create the Resources folder in the Contents folder;
  • copy the “MyProject_Directory\OSX32\Release\MyProject.icns” file to the Resources folder.

After performing these steps you can run the MyProject.app application package on Mac OS X.

Specificity of deploying applications that use Devart Data Access Components

Applications using some of the Devart Data Access Components products require database client libraries to function on Mac OS X. Client libraries can be located in public libraries directory (for example, /usr/lib ) or in the MacOS folder of the application package. The table below shows the required client libraries for each particular Devart Data Access Components:

DAC Mode
Direct Client
ODAC Not required Oracle client
MyDAC Not required libmysql.dylib
IBDAC for InterBase: libibtogo.dylib
for Firebird: libfbclient.dylib
PgDAC Not required not supported
SQLite (by UniDAC) not supported libsqlite3.dylib
UniDAC Correspondent libraries for used data provider

Specificity of deploying applications that use Devart dbExpress drivers

Applications using some of the Devart dbExpress drivers products require database client libraries plus the libmidas.dylib library and the correspondent dbExpress driver library to function on Mac OS X. All required libraries can be located in the public libraries directory (for example, /usr/lib ) or in the MacOS folder of the application package. The table below shows all required libraries for each particular dbExpress driver:

dbExpress driver Mode
Direct Client
dbExpress driver for Oracle libmidas.dylib
libdbexpoda40.dylib
libmidas.dylib
libdbexpoda40.dylib
Oracle client
dbExpress driver for MySQL libmidas.dylib
libdbexpmda40.dylib
libmidas.dylib
libdbexpmda40.dylib
libmysql.dylib
dbExpress driver for InterBase & Firebird libmidas.dylib
libdbexpida40.dylib
for InterBase: libibtogo.dylib
for Firebird: libfbclient.dylib
dbExpress driver for PostgreSQL libmidas.dylib
libdbexppgsql40.dylib
dbExpress driver for SQLite not supported libmidas.dylib
libdbexpsqlite40.dylib
libsqlite3.dylib

Delphi XE2 FireMonkey HD Applications Raise Runtime Error 231 on Mac OS X

October 5th, 2011

Many users have encountered the problem when running FireMonkey HD Applications on Mac OS X without 3D hardware HAL. When this application is run, it either freezes or produces the following error:

Runtime error 231 at 000169AD

We have researched this problem and found a solution from Embarcadero. If a Mac OS X computer has no 3D hardware HAL, you need to set the global variable FMX.Types.GlobalUseHWEffects to False. Example:

begin
  FMX.Types.GlobalUseHWEffects := False;

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end;

However, this solution is not a panacea. Sometimes HD Applications continue to freeze or raise the error even with FMX.Types.GlobalUseHWEffects set to False. In this case, you need to modify the FMX.Filter.pas unit. Do the following:

  1. Copy the FMX.Filter.pas and FMX.Defines.inc files from the $(BDS)\source\fmx\ folder to your project folder.
  2. In the files copied to your project folder replace the code of the FilterByName and FilterClassByName functions with the following code:
    function FilterByName(const AName: string): TFilter;
    var
      i: Integer;
    begin
      Result := nil;
      if not GlobalUseHWEffects or (Filters = nil) then // <-- change this line
        Exit;
      for i := 0 to Filters.Count - 1 do
        if CompareText(TFilterClass(Filters.Objects[i]).FilterAttr.Name, AName) = 0
      then
      begin
        Result := TFilterClass(Filters.Objects[i]).Create;
        Exit;
      end;
    end;
    
    function FilterClassByName(const AName: string): TFilterClass;
    var
      i: Integer;
    begin
      Result := nil;
      if not GlobalUseHWEffects or (Filters = nil) then // <-- change this line
        Exit;
      for i := 0 to Filters.Count - 1 do
        if CompareText(TFilterClass(Filters.Objects[i]).FilterAttr.Name, AName) = 0
        then
        begin
          Result := TFilterClass(Filters.Objects[i]);
          Exit;
        end;
    end;
  3. Add the FMX.Filter unit to the USES section of your project:
    program Project1;
    
    uses
      FMX.Forms,
      FMX.Types,
      FMX.Filter, // <-- add unit
      Unit1 in 'Unit1.pas' {Form1};

After such modifications your applications will run successfully on Mac OS X without 3D hardware HAL; however, 3D effects will not be available for it.

Updated:
This trick is not required for Rad Studio XE2 with Update 3 and higher.

64-bit Development with Delphi XE2

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

  3. Select Linking in the left part of the Project Options form.
  4. 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:\Windows\SysWOW64 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:\Windows\System32 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.


DAC Team's Blog