Tải bản đầy đủ (.pdf) (111 trang)

Developer’s Guide Borland Delphi 7 for Windows PHẦN 4 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (638.2 KB, 111 trang )

Exception handling
14-11
Handling exceptions in VCL applications
There are other times when you will need to create your own exception classes to
handle unique situations. You can declare a new exception class by making it a
descendant of type Exception and creating as many constructors as you need (or copy
the constructors from an existing class in the SysUtils unit).
Default exception handling in VCL
If your application code does not catch and handle the exceptions that are raised, the
exceptions are ultimately caught and handled by the HandleException method of the
global Application object. For all exceptions but EAbort, HandleException calls the
OnException event handler, if one exists. If there is no OnException event handler (and
the exception is not EAbort), HandleException displays a message box with the error
message associated with the exception.
EDBEditError Catches data incompatible with a specified mask.
EDivByZero Catches integer divide-by-zero errors.
EExternalException Signifies an unrecognized exception code.
EInOutError Represents a file I/O error.
EIntOverflow Specifies integer calculations whose results are too large for the allocated
register.
EInvalidCast Checks for illegal typecasting.
EInvalidGraphic Indicates an attempt to work with an unrecognized graphic file format.
EInvalidOperation Occurs when invalid operations are attempted on a component.
EInvalidPointer Results from invalid pointer operations.
EMenuError Involves a problem with menu item.
EOleCtrlError Detects problems with linking to ActiveX controls.
EOleError Specifies OLE automation errors.
EPrinterError Signals a printing error.
EPropertyError Occurs on unsuccessful attempts to set the value of a property.
ERangeError Indicates an integer value that is too large for the declared type to which it is
assigned.


ERegistryException Specifies registry errors.
EZeroDivide Catches floating-point divide-by-zero errors.
Table 14.1 Selected exception classes (continued)
Exception class Description
14-12
Developer’ s Guide
Handling exceptions in VCL applications
There are certain circumstances where HandleException does not get called.
Exceptions that occur before or after the execution of the application’s Run method
are not caught and handled by HandleException. When you write a callback function
or a library (.dll or shared object) with functions that can be called by an external
application, exceptions can escape the Application object. To prevent exceptions from
escaping in this manner, you can insert your own call to the HandleException method:
try
{ special statements }
except
on Exception do
begin
Application.HandleException(Self);{ call HandleException }
end;
end;
Warning
Do not call HandleException from a thread’s exception handling code.
Silent exceptions
VCL applications handle most exceptions that your code doesn't specifically handle
by displaying a message box that shows the message string from the exception object.
You can also define “silent” exceptions that do not, by default, cause the application
to show the error message.
Silent exceptions are useful when you don't intend to report an exception to the user,
but you want to abort an operation. Aborting an operation is similar to using the

Break or Exit procedures to break out of a block, but can break out of several nested
levels of blocks.
Silent exceptions all descend from the standard exception type EAbort. The default
exception handler for VCL applications displays the error-message dialog box for all
exceptions that reach it except those descended from EAbort.
Note
For console applications, an error-message dialog is displayed on any unhandled
EAbort exceptions.
There is a shortcut for raising silent exceptions. Instead of manually constructing the
object, you can call the Abort procedure. Abort automatically raises an EAbort
exception, which breaks out of the current operation without displaying an error
message.
Note
There is a distinction between Abort and abort. abort kills the application.
Exception handling
14-13
Handling exceptions in VCL applications
The following code shows a simple example of aborting an operation. On a form
containing an empty list box and a button, attach the following code to the button's
OnClick event:
procedure TForm1.Button1Click(Sender: TObject);
var
I, J: Integer;
begin
for I := 1 to 10 do{ loop ten times }
for J := 1 to 10 do {loop ten times }
begin
ListBox1.Items.Add(IntToStr(I) + IntToStr(J));
if I = 7 then Abort;{ abort after the 7th iteration of outer loop}
end;

end;
Note that in this example, Abort causes the flow of execution to break out of both the
inner and outer loops, not just the inner loop.
Defining your own VCL exceptions
Because VCL exceptions are classes, defining a new kind of exception is as simple as
declaring a new class type. Although you can raise any object instance as an
exception, the standard VCL exception handlers handle only exceptions that descend
from Exception.
New exception classes should be derived from Exception or one of the other standard
exceptions. That way, if you raise your new exception in a block of code that isn't
protected by an exception handler specific to that exception, one of the standard
handlers will handle it instead.
For example, consider the following declaration:
type
EMyException = class(Exception);
If you raise EMyException but don't provide a specific handler for it, a handler for
Exception (or a default exception handler) will still handle it. Because the standard
handling for Exception displays the name of the exception raised, you can see that it is
your new exception that is raised.
.
14-14
Developer’ s Guide
Developing cross-platform applications
15-1
Chapter
15
Chapter15
Developing cross-platform
applications
You can develop cross-platform 32-bit applications that run on both the Windows

and Linux operating systems. Cross-platform applications use CLX components
from the Borland Component Library for Cross-Platform (CLX) and don’t make any
operating system-specific API calls.
This chapter describes how to change Delphi applications so they can compile on
Windows or Linux and how to write code that is platform-independent and portable
between the two environments. It also includes information on the differences
between developing applications on Windows and Linux.
To develop a cross-platform application, either:
• Create a new CLX application.
• Modify an existing VCL application.
Then compile, test, and deploy it on the platform you are running it on. For Windows
cross-platform applications, use Delphi. For Linux cross-platform applications, use
Kylix. Kylix is Borland’s Delphi and C++ software that allows you to develop and
deploy applications on Linux.
You can also develop a cross-platform application by starting on Kylix instead of
Windows and transfer it to Windows
Note
CLX applications are not available in all editions of Delphi.
15-2
Developer’ s Guide
Creating CLX applications
Creating CLX applications
You create CLX applications in nearly the same way as you create any Delphi
application.
1
In the IDE, choose File|New|CLX application.
The Component palette displays the pages and components that can be used in
CLX applications.
2
Develop your application within the IDE. Remember to use only CLX components

in your application.
3
Compile and test the application on each platform on which you want to run the
application. Review any error messages to see where additional changes need to
be made.
To compile the application on Kylix, you must first transfer your application to
your Linux computer.
To modify a VCL application as a cross-platform application, see Modifying VCL
applications. For tips on writing cross-platform application, see “Writing portable
code” on page 15-12. For information on writing platform-independent database or
Internet applications, see “Cross-platform database applications” on page 15-21 and
“Cross-platform Internet applications” on page 15-28.
Porting VCL applications
If you have Borland RAD applications that were written for the Windows
environment, you can port them to the Linux environment. How easy it will be
depends on the nature and complexity of the application and how many Windows
dependencies there are.
The following sections describe some of the major differences between the Windows
and Linux environments and provide guidelines on how to get started porting an
application.
Porting techniques
The following are different approaches you can take to port an application from one
platform to another:
Table 15.1 Porting techniques
Technique Description
Platform-specific port Targets an operating system and underlying APIs.
Cross-platform port Targets a cross-platform API.
Windows emulation Leaves the code alone and ports the API it uses.
Developing cross-platform applications
15-3

Porting VCL applications
Platform-specific ports
Platform-specific ports tend to be time-consuming, expensive, and only produce a
single targeted result. They create different code bases, which makes them
particularly difficult to maintain. However, each port is designed for a specific
operating system and can take advantage of platform-specific functionality. Thus, the
application typically runs faster.
Cross-platform ports
Cross-platform ports tend to be time-saving because the ported applications target
multiple platforms. However, the amount of work involved in developing cross-
platform applications is highly dependent on the existing code. If code has been
developed without regard for platform independence, you may run into scenarios
where platform-independent logic and platform-dependent implementation are
mixed together.
The cross-platform approach is the preferable approach because business logic is
expressed in platform-independent terms. Some services are abstracted behind an
internal interface that looks the same on all platforms, but has a specific
implementation on each. The runtime library is an example of this. The interface is
very similar on both platforms, although the implementation may be vastly different.
You should separate cross-platform parts, then implement specific services on top. In
the end, this approach is the least expensive solution, because of reduced
maintenance costs due to a largely shared source base and an improved application
architecture.
Windows emulation ports
Windows emulation is the most complex method and it can be very costly, but the
resulting Linux application will look most similar to an existing Windows
application. This approach involves implementing Windows functionality on Linux.
From an engineering point of view, this solution is very hard to maintain.
Where you want to emulate Windows APIs, you can include two distinct sections
using conditional compiler directives (such as $IFDEFs) to indicate sections of the

code that apply specifically to Windows or Linux.
15-4
Developer’ s Guide
Porting VCL applications
Modifying VCL applications
If you are porting a VCL application to Linux that you want to run on both Windows
and Linux, you may need to modify your code or use conditional compiler directives
to indicate sections of the code that apply specifically to Windows or Linux.
To modify your VCL application so that it can run on Linux, follow these general
steps:
1
In Windows, open the project containing the VCL application you want to change.
2
Rename your form files (.dfm) to cross-platform form files (.xfm). For example,
rename unit1.dfm to unit1.xfm. Or add an $IFDEF compiler directive. An .xfm
form file works on both Windows or Linux but a .dfm form only works on
Windows.
Change {$R *.dfm} to {$R *.xfm} in the implementation section.
3
Change all uses clauses in your source file so they refer to the correct units in
VisualCLX. (See “Comparing WinCLX and VisualCLX units” on page 15-8 for
information.)
For example, change the following uses clause:
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
to the following:
uses SysUtils, Types, Classes, QGraphics, QControls, QForms, QDialogs, QStdCtrls;
4
Save the project and reopen it. Now the Component palette shows components
that can be used in CLX applications.

Note
Some Windows-only nonvisual components can be used in cross-platform
applications but only work in Windows cross-platforms applications. If you plan
to compile your application on Linux as well, either do not use the nonvisual
WinCLX components in your applications or use $IFDEFs to mark these sections
of the code as Windows only. You cannot use the visual part of WinCLX with
VisualCLX in the same application.
5
Rewrite any code that requires Windows dependencies by making the code more
platform-independent. Do this using the runtime library routines and constants.
(See “Cross-platform database applications” on page 15-21 for information.)
6
Find equivalent functionality for features that are different on Linux. Use
conditional compiler directives such as $IFDEFs (sparingly) to delimit Windows-
specific information. (See “Using conditional directives” on page 15-13 for
information.)
Developing cross-platform applications
15-5
Porting VCL applications
For example, you can use conditional compiler directives for platform-specific
code in your source files:
{$IFDEF MSWINDOWS}
IniFile.LoadfromFile(‘c:\x.txt’);
{$ENDIF}
{$IFDEF LINUX}
IniFile.LoadfromFile(‘/home/name/x.txt’);
{$ENDIF}
7
Search for references to pathnames in all the project files.
• Pathnames in Linux use a forward slash / as a delimiter (such as /usr/lib) and

files may be located in different directories on the Linux system. Use the
PathDelim constant (in SysUtils) to specify the path delimiter that is
appropriate for the system. Determine the correct location for any files on
Linux.
• Change references to drive letters (for example, C:\) and code that looks for
drive letters by looking for a colon at position 2 in the string. Use the
DriveDelim constant (in SysUtils) to specify the location in terms that are
appropriate for the system.
• In places where you specify multiple paths, change the path separator from
semicolon (;) to colon (:). Use the PathSep constant (in SysUtils) to specify the
path separator that is appropriate for the system.
• Because file names are case-sensitive in Linux, make sure that your application
doesn’t change the case of file names or assume a certain case.
See “Programming differences on Linux” on page 15-16.
WinCLX versus VisualCLX
CLX applications use the Borland Component Library for Cross-Platform (CLX) in
place of the Visual Component Library (VCL). Both the VCL and CLX include the
same four out of five sublibraries, as described in “Understanding the component
library” on page 3-1. The classes and properties in these sublibraries have the same
names. The only differences between the VCL and CLX are the classes in the WinCLX
and VisualCLX sublibraries. VCL applications use WinCLX whereas CLX
applications use VisualCLX.
Within WinCLX, many controls access Windows controls by making calls into the
Windows API libraries. Similarly, in the VisualCLX the controls provide access to Qt
widgets by making calls into the Qt shared libraries.
Widgets in VisualCLX replace Windows controls. For example, TWidgetControl in
CLX replaces TWinControl in WinCLX. Other WinCLX components (such as
TScrollingWinControl) have corresponding names in VisualCLX (such as
TScrollingWidget). However, you do not need to change occurrences of TWinControl
to TWidgetControl. Class declarations, such as the following:

TWinControl = TWidgetControl;
15-6
Developer’ s Guide
Porting VCL applications
appear in the QControls unit file to simplify sharing of source code. TWidgetControl
and all its descendants have a Handle property that references the Qt object and a
Hooks property that references the hook object that handles the event mechanism.
Unit names and locations of some classes are different in CLX. You will need to
modify the uses clauses you include in your source files to eliminate references to
units that don’t exist in VisualCLX and to change the names to CLX units. Most
project files and the interface sections of most units contain a uses clauses. The
implementation section of a unit can also contain its own uses clause.
What VisualCLX does differently
Although much of VisualCLX is implemented so that it is consistent with WinCLX,
some components are implemented differently. This section describes some of those
differences to be aware of when writing CLX applications.
•The VisualCLX TButton control has a ToggleButton property that the equivalent
WinCLX control doesn’t have.
•In VisualCLX, TColorDialog does not have an Options property. Therefore, you
cannot customize the appearance and functionality of the color selection dialog.
Also, depending on which window manager you are using in Linux, TColorDialog
is not always modal or nonresizable. On Windows, TColorDialog is always modal
and nonresizable.
• At runtime, combo boxes work differently in VisualCLX than they do in WinCLX.
In VisualCLX (but not in WinCLX), you can add an item to a drop-down list by
entering text and pressing
Enter
in the edit field of a combo box. You can turn this
feature off by setting InsertMode to ciNone. It is also possible to add empty (no
string) items to the list in the combo box. Also, if you keep pressing the down

arrow key when the edit box is closed, it does not stop at the last item of the combo
box list. It cycles around to the top again.
• The key values used in events can be different between WinCLX and VisualCLX.
For example, the
Enter
key has a value of 13 on WinCLX and a value of 4100 on
VisualCLX. If you hard code key values in your VisualCLX applications, you need
to change these values when porting from Windows to Linux or vice versa.
• Application-wide styles can be used in addition to the OwnerDraw properties. You
can use TApplication’s Style property to specify the look and feel of an application's
graphical elements. Using styles, a widget or an application can take on a whole
new look. You can still use owner draw on Linux but using styles is
recommended.
Some VisualCLX classes are missing certain properties, methods, or events:
• Bi-directional properties (BidiMode) for right-to-left text output or input.
• Generic bevel properties on common controls (note that some objects still have
bevel properties).
• Docking properties and methods.
• Backward compatibility components such as those on the Win3.1 tab and Ctl3D.
• DragCursor and DragKind (but drag and drop is included).
Developing cross-platform applications
15-7
Porting VCL applications
Additional differences exist. Refer to the CLX online documentation for details on all
of the CLX objects or in editions of Delphi that include the source code, located in
{install directory}\Delphi\Source\Clx.
Features that do not port directly or are missing
In general, the functionality between VCL and CLX applications is the same.
However, some Windows-specific features do not port directly to Linux
environments. For example, ActiveX, ADO, BDE, COM, and OLE are dependent on

Windows technology and not available in Kylix. The following table lists features
that are different on the two platforms and lists the equivalent Linux or VisualCLX
feature, if one is available.
Other features not supported or supported differently on Kylix include:
• The Linux equivalent of Windows DLLs are shared object libraries (.so files),
which contain position-independent code (PIC). Thus, global memory references
and calls to external functions are made relative to the EBX register, which must be
preserved across calls. This means that variables referring to an absolute address
in memory (using the absolute directive) are not allowed on Linux. You only need
to worry about global memory references and calls to external functions if using
assembler—Delphi generates the correct code. (For information, see “Including
inline assembler code” on page 15-15.)
• Absolute addresses are used in variable declarations. You can use the absolute
directive to refer to the name of another variable; for example:
var Var2: Byte absolute Var1;
• Library modules and packages, which are implemented using .so files.
Table 15.2 Changed or different features
Windows/VCL feature Linux/CLX feature
ADO components Regular database components
Automation Servers Not available
BDE dbExpress and regular database components
COM+ components (including ActiveX) Not available
DataSnap Functionality for Web Services only
FastNet Not available
Legacy components (such as items on the Win 3.1
Component palette tab)
Not available
Messaging Application Programming Interface
(MAPI) includes a standard library of Windows
messaging functions

SMTP and POP3 let you send, receive, and
save e-mail messages
Windows API calls VisualCLX methods, Qt calls, libc calls, or
calls to other system libraries
Windows messaging Qt events
Winsock BSD sockets
15-8
Developer’ s Guide
Porting VCL applications
• Borland's make utility. Use the GNU make utility instead.
• TASM is not supported. You cannot import external assembler routines unless
they use syntax supported by an assembler such as NASM, the Netwide
Assembler, one of the free, portable x86 assemblers supported by Kylix.
• Resource introspection is not supported. Applications must know at compile time
the names of all resources they will use. Resources cannot be browsed
dynamically.
Comparing WinCLX and VisualCLX units
All of the objects in the component library are defined in unit files. For example, you
can find the implementation of TObject in the System unit and the base TComponent
class defined in the Classes unit. When you drop an object onto a form or use an
object within your application, the name of the unit is added to the uses clause,
which tells the compiler which units to link into the project.
Some of the units that are in VCL applications are also in CLX applications, such as
Classes, DateUtils, DB, System, SysUtils and many more units such as those in the
runtime library (RTL). However, the CLX units in the VisualCLX sublibrary are
different from those in the WinCLX sublibrary. If you are porting VCL applications
from Windows to Linux, you’ll have to change the names of these units in the uses
clause of your application. The most common name change is made by adding a Q to
the beginning of the unit or header file name.
This section provides three tables that list the WinCLX-only and equivalent

VisualCLX units; VisualCLX-only units; and WinCLX-only units.
Table 15.3 lists the names of WinCLX units that have different names than the
VisualCLX units. Units that are either the same in both VCL and CLX applications or
are third-party units are not listed.
Table 15.3 WinCLX-only and equivalent VisualCLX units
WinCLX units VisualCLX units
ActnList QActnList
Buttons QButtons
CheckLst QCheckLst
Clipbrd QClipbrd
ComCtrls QComCtrls
Controls QControls
DBActns QDBActns
DBCtrls QDBCtrls
DBGrids QDBGrids
Dialogs QDialogs
ExtCtrls QExtCtrls
Forms QForms
Graphics QGraphics
Developing cross-platform applications
15-9
Porting VCL applications
The following units are VisualCLX-only units:
The following Windows-only units are not included in CLX applications mostly
because they concern Windows-specific features that are not available on Linux. For
example, CLX applications do not use ADO units, BDE units, COM units, or
Windows units such as CtlPanel, Messages, Registry, and Windows.
Grids QGrids
ImgList QImgList
Mask QMask

Menus QMenus
Printers QPrinters
Search QSearch
StdActns QStdActns
StdCtrls QStdCtrls
VclEditors ClxEditors
Table 15.4 VisualCLX-only units
Unit Description
DirSel Directory selection
QStyle GUI look and feel
Qt Interface to Qt library
Table 15.5 WinCLX-only units
Unit Reason for exclusion
ADOConst No ADO feature
ADODB No ADO feature
AppEvnts No TApplicationEvent object
AxCtrls No COM feature
BdeConst No BDE feature
Calendar Not currently supported
Chart Not currently supported
CmAdmCtl No COM feature
ColorGrd Not currently supported
ComStrs No COM feature
ConvUtils Not available
CorbaCon No Corba feature
CorbaStd No Corba feature
CorbaVCL No Corba feature
CtlPanel No Windows Control Panel
CustomizeDlg Not currently supported
Table 15.3 WinCLX-only and equivalent VisualCLX units (continued)

WinCLX units VisualCLX units
15-10
Developer’ s Guide
Porting VCL applications
DataBkr Not currently supported
DBCGrids No BDE feature
DBExcept No BDE feature
DBInpReq No BDE feature
DBLookup Obsolete
DbOleCtl No COM feature
DBPWDlg No BDE feature
DBTables No BDE feature
DdeMan No DDE feature
DRTable No BDE feature
ExtActns Not currently supported
ExtDlgs No picture dialogs feature
FileCtrl Obsolete
ListActns Not currently supported
MConnect No COM feature
Messages No Windows messaging
MidasCon Obsolete
MPlayer No Windows media player
Mtsobj No COM feature
MtsRdm No COM feature
Mtx No COM feature
mxConsts No COM feature
ObjBrkr Not currently supported
OleConstMay No COM feature
OleCtnrs No COM feature
OleCtrls No COM feature

OLEDB No COM feature
OleServer No COM feature
Outline Obsolete
Registry No Windows registry feature
ScktCnst Replaced by Sockets
ScktComp Replaced by Sockets
SConnect No supported connection protocols
SHDocVw_ocx No ActiveX feature
StdConvs Not currently supported
SvcMgr No Windows NT Services feature
TabNotbk Obsolete
Tabs Obsolete
ToolWin No docking feature
ValEdit Not currently supported
Table 15.5 WinCLX-only units (continued)
Unit Reason for exclusion
Developing cross-platform applications
15-11
Porting VCL applications
References to these units and the classes within these units must be eliminated from
applications you want to run on Linux. If you try to compile a program with units
that do not exist in a cross-platform application, you will receive the following error
message:
File not found: ‘unitname.dcu’
Delete that unit from the uses clause and try again.
Differences in CLX object constructors
A CLX object is created either implicitly by placing that object on the form or
explicitly in code by using the object’s Create method. When the CLX object is created,
an instance of the underlying associated widget is also created (as long as the widget
is parented or its handle referenced). The CLX object owns this instance of the

widget. When the CLX object is deleted, the underlying widget is also deleted. The
object is deleted by calling the Free method or automatically deleted by the CLX
object's parent container. This is the same type of functionality that you see in the
component library in Windows-only applications.
When you explicitly create a CLX object in your code by calling into the Qt interface
library such as QWidget_Create(), you are creating an instance of a Qt widget that is
not owned by a CLX object. This passes the instance of an existing Qt widget to the
CLX object to use during its construction. This CLX object does not own the Qt
widget that is passed to it. Therefore, when you call the Free method after creating the
object in this manner, only the CLX object is destroyed and not the underlying Qt
widget instance. This is different from a VCL application.
A few CLX graphics objects, such as TBrush and TPen, let you assume ownership of
the underlying widget using the OwnHandle method. After calling OwnHandle, if you
delete the CLX object, the underlying widget is destroyed as well.
Some property assignments in CLX have moved from the Create method to
InitWidget. This allows delayed construction of the Qt object until it's really needed.
For example, say you have a property named Color. In SetColor, you can check with
HandleAllocated to see if you have a Qt handle. If the handle is allocated, you can
make the proper call to Qt to set the color. If not, you can store the value in a private
field variable, and, in InitWidget, you set the property.
VarCmplx Not currently supported
VarConv Not currently supported
VCLCom No COM feature
WebConst No Windows constants
Windows No Windows API calls
Table 15.5 WinCLX-only units (continued)
Unit Reason for exclusion
15-12
Developer’ s Guide
Porting VCL applications

Handling system and widget events
System and widget events, which are mainly of concern when writing components,
are handled differently by the VCL and CLX. The most important difference is that
VisualCLX controls do not respond directly to Windows messages, even when
running on Windows (see Chapter 7, “Handling messages and system notifications,”
in the Component Writer’s Guide.) Instead, they respond to notifications from the
underlying widget layer. Because the notifications use a different system, the order
and timing of events can sometimes differ between corresponding the VCL and CLX
objects. This difference occurs even if your CLX application is running on Windows
rather than Linux. If you are porting a VCL application to Linux, you may need to
change the way your event handlers respond to accommodate these differences.
For information on writing components that respond to system and widget events
(other than those that are reflected in the published events of CLX components), see
“Responding to system notifications using CLX” on page 7-18 of the Component
Writer’s Guide.
Writing portable code
If you are writing cross-platform applications that are meant to run on both
Windows and Linux, you can write code that compiles under different conditions.
Using conditional compilation, you can maintain your Windows coding, yet also
make allowances for Linux operating system differences.
To create applications that are easily portable between Windows and Linux,
remember to:
• Reduce or isolate calls to platform-specific (Win32 or Linux) APIs; use CLX
methods or calls to the Qt library.
• Eliminate Windows messaging (PostMessage, SendMessage) constructs within an
application. In CLX, call the QApplication_postEvent and QApplication_sendEvent
methods instead. For information on writing components that respond to system
and widget events, see “Responding to system notifications using CLX” on
page 7-18 of the Component Writer’s Guide.
•Use TMemIniFile instead of TRegIniFile.

• Observe and preserve case-sensitivity in file and directory names.
• Port any external assembler TASM code. The GNU assembler, “as,” does not
support the TASM syntax. (See “Including inline assembler code” on page 15-15.)
Try to write the code to use platform-independent runtime library routines and use
constants found in System, SysUtils, and other runtime library units. For example,
use the PathDelim constant to insulate your code from ‘/’ versus ‘\’ platform
differences.
Developing cross-platform applications
15-13
Porting VCL applications
Another example involves the use of multibyte characters on both platforms.
Windows code traditionally expects only two bytes per multibyte character. In Linux,
multibyte character encoding can have many more bytes per char (up to six bytes for
UTF-8). Both platforms can be accommodated using the StrNextChar function in
SysUtils.
Code such as:
while p^ <> #0 do
begin
if p^ in LeadBytes then
inc(p);
inc(p);
end;
can be replaced with platform-independent code such as this:
while p^ <> #0 do
begin
if p^ in LeadBytes then
p := StrNextChar(p)
else
inc(p);
end;

The previous example is platform-portable but still avoids the performance cost of a
procedure call for non-multibyte locales.
If using runtime library functions is not a workable solution, try to isolate the
platform-specific code in your routine into one chunk or into a subroutine. Try to
limit the number of conditional compiler directive ($IFDEF) blocks to maintain
source code readability and portability. The conditional symbol WIN32 is not defined
on Linux. The conditional symbol LINUX is defined, indicating the source code is
being compiled for the Linux platform.
Using conditional directives
Using conditional compiler directives such as $IFDEF is a reasonable way to
conditionalize your code for the Windows and Linux platforms. However, because
conditional compiler directives make source code harder to understand and
maintain, you need to understand when it is reasonable to use them. When
considering the use of conditional compiler directive, think about whether the code
requires a conditional compiler directive and whether it can be written without a
conditional compiler directive.
15-14
Developer’ s Guide
Porting VCL applications
Follow these guidelines for using conditional compiler directives within cross-
platform applications:
• Try not to use $IFDEFs unless absolutely necessary. $IFDEFs in a source file are
only evaluated when source code is compiled. Delphi does not require unit
sources to compile a project. Full rebuilds of all source code is an uncommon event
for most Delphi projects.
•Do not use $IFDEFs in package (.dpk) files. Limit their use to source files.
Component writers need to create two design-time packages when doing cross-
platform development, not one package using $IFDEFs.
• In general, use $IFDEF MSWINDOWS to test for any Windows platform
including WIN32. Reserve the use of $IFDEF WIN32 for distinguishing between

specific Windows platforms, such as 32-bit versus 64-bit Windows. Don’t limit
your code to WIN32 unless you know for sure that it will not work in WIN64.
• Avoid negative tests like $IFNDEF unless absolutely required. $IFNDEF LINUX
is not equivalent to $IFDEF MSWINDOWS.
•Avoid $IFNDEF/$ELSE combinations. Use a positive test instead ($IFDEF) for
better readability.
•Avoid $ELSE clauses on platform-sensitive $IFDEFs. Use separate $IFDEF blocks
for Linux- and Windows-specific code instead of $IFDEF LINUX/$ELSE or
$IFDEF MSWINDOWS/$ELSE.
For example, old code may contain:
{$IFDEF WIN32}
(32-bit Wi1ndows code)
{$ELSE}
(16-bit Windows code) //!! By mistake, Linux could fall into this code.
{$ENDIF}
For any non-portable code in $IFDEFs, it is better for the source code to fail to
compile than to have the platform fall into an $ELSE clause and fail mysteriously
at runtime. Compile failures are easier to find than runtime failures.
•Use the $IF syntax for complicated tests. Replace nested $IFDEFs with a boolean
expression in an $IF directive. You should terminate the $IF directive using
$IFEND, not $ENDIF. This allows you to place $IF expressions within $IFDEFs to
hide the new $IF syntax from previous compilers.
All of the conditional directives are documented in the online Help. Also, see the
topic “conditional directives” in Help for more information.
Terminating conditional directives
Use the $IFEND directive to terminate $IF and $ELSEIF conditional directives. This
allows $IF/$IFEND blocks to be hidden from older compilers inside of using $IFDEF/
$ENDIF. Older compilers won't recognize the $IFEND directive. $IF can only be
terminated with $IFEND. You can only terminate old-style directives ($IFDEF,
$IFNDEF, $IFOPT) with $ENDIF.

Developing cross-platform applications
15-15
Porting VCL applications
Note
When nesting an $IF inside of $IFDEF/$ENDIF, do not use $ELSE with the $IF.
Older compilers will see the $ELSE and think it is part of the $IFDEF, producing a
compile error down the line. You can use {$ELSE True} as a substitute for {$ELSE} in
this situation, since the $ELSE won't be taken if the $IF is taken first, and the older
compilers won't know $ELSEIF. Hiding $IF for backwards compatibility is primarily
an issue for third party vendors and application developers who want their code to
run on several different versions.
$ELSEIF is a combination of $ELSE and $IF. The $ELSEIF directive allows you to
write multi-part conditional blocks where only one of the conditional blocks will be
taken. For example:
{$IFDEF doit}
do_doit
{$ELSEIF RTLVersion >= 14}
goforit
{$ELSEIF somestring = 'yes'}
beep
{$ELSE}
last chance
{$IFEND}
Of these four cases, only one is taken. If none of the first three conditions is true, the
$ELSE clause is taken. $ELSEIF must be terminated by $IFEND. $ELSEIF cannot
appear after $ELSE. Conditions are evaluated top to bottom like a normal
$IF $ELSE sequence. In the example, if doit is not defined, then RTLVersion is 15
and somestring is 'yes.' Only the “goforit” block is taken and not the “beep” block,
even though the conditions for both are true.
If you forget to use an $ENDIF to end one of your $IFDEFs, the compiler reports the

following error message at the end of the source file:
Missing ENDIF
If you have more than a few $IF/$IFDEF directives in your source file, it can be
difficult to determine which one is causing the problem. The following error message
appears on the source line of the last $IF/$IFDEF compiler directive with no
matching $ENDIF/$IFEND:
Unterminated conditional directive
You can start looking for the problem at that location.
Including inline assembler code
If you include inline assembler code in your Windows applications, you may not be
able to use the same code on Linux because of position-independent code (PIC)
requirements on Linux. Linux shared object libraries (DLL equivalents) require that
all code be relocatable in memory without modification. This primarily affects inline
assembler routines that use global variables or other absolute addresses, or that call
external functions.
For units that contain only Delphi code, the compiler automatically generates PIC
when required. It's a good idea to compile every unit into both PIC and non-PIC
formats; use the -p compiler switch to generate PIC.
15-16
Developer’ s Guide
Porting VCL applications
Precompiled units are available in both PIC and non-PIC formats. PIC units have a
.dpu extension (instead of .dcu).
You may want to code assembler routines differently depending on whether you'll
be compiling to an executable or a shared library; use {$IFDEF PIC} to branch the two
versions of your assembler code. Or you can consider rewriting the routine in the
Delphi language to avoid the issue.
Following are the PIC rules for inline assembler code:
• PIC requires all memory references be made relative to the EBX register, which
contains the current module's base address pointer (in Linux called the Global

Offset Table or GOT). So, instead of
MOV EAX,GlobalVar
use
MOV EAX,[EBX].GlobalVar
• PIC requires that you preserve the EBX register across calls into your assembly
code (same as on Win32), and also that you restore the EBX register before making
calls to external functions (different from Win32).
• While PIC code will work in base executables, it may slow the performance and
generate more code. You don't have any choice in shared objects, but in
executables you probably still want to get the highest level of performance that
you can.
Programming differences on Linux
The Linux wchar_t widechar is 32 bits per character. The 16-bit Unicode standard
that forms the basis of the WideString type is a subset of the 32-bit UCS standard
supported by Linux and the GNU libraries. References to WideString must be
widened to 32 bits per character before they can be passed to an OS function as
wchar_t. In Linux, WideStrings are reference counted like long strings (in Windows,
they're not).
In Windows, multibyte characters (MBCS) are represented as one- and two-byte char
codes. In Linux, they are represented as one to six bytes.
The Delphi language string type (long strings) can carry multibyte character
sequences, depending upon the user's locale settings. The Linux encoding for
multibyte characters such as Japanese, Chinese, Hebrew, and Arabic may not be
compatible with the Windows encoding for the same locale. Unicode is portable,
whereas multibyte is not. See “Enabling application code” on page 17-2 for details on
handling strings for various locales in international applications.
In Linux, you cannot use variables on absolute addresses. The syntax:
var X: Integer absolute $1234;
is not supported in PIC and is not allowed in a CLX application.
Developing cross-platform applications

15-17
Transferring applications between Windows and Linux
Transferring applications between Windows and Linux
If you’ve created a new CLX application or modified an existing VCL application on
Delphi and are porting it to Kylix, or you have created a CLX application on Kylix
and are porting it to Delphi, you transfer your files in the same way.
1
Move your application source files and other project-related files from one
platform to the other. You can share source files between Linux and Windows if
you want the program to run on both platforms. Or you can transfer the files using
a tool such as ftp using the ASCII mode.
Source files should include your unit files (.pas files), project files (.dpr), and any
package files (.dpk files). Project-related files include form files (.dfm or .xfm files),
resource files (.res files), and project options file (.dof in Delphi and .kof in Kylix).
If you want to compile your application from the command line only (rather than
using the IDE), you’ll need the configuration file (.cfg file in Delphi and .conf in
Kylix). You may need to change the paths of the units in your main project.
2
Open the project on the platform to which you are porting.
3
Reset your project options.
The file that stores the default project options is recreated on Kylix with a .kof
extension and recreated on Windows with a .dof extension. In the Delphi IDE, you
can also store many of the compiler options with the application by typing
Ctrl+O+O
. The options are placed at the beginning of the currently open file.
4
Compile, test, and debug your application.
For VCL applications you transfer to Kylix, you will receive warnings on
Windows-specific features in the application.

Sharing source files between Windows and Linux
If you want your application to run on both Windows and Linux, you can share the
source files making them accessible to both operating systems. You can do this in
several ways, such as placing the source files on a server that is accessible to both
computers or by using Samba on the Linux machine to provide access to files
through Microsoft network file sharing for both Linux and Windows. You can choose
to keep the source on Linux and create a shared drive on Linux. Or you can keep the
source on Windows and create a share on Windows for the Linux machine to access.
You can continue to develop and compile the file on Kylix using objects that are
supported by CLX. When you are finished, you can compile on both Linux and
Windows.
If you create a new CLX application in Delphi, the IDE creates an .xfm form file
instead of a .dfm file. If you want to single-source your code, you should copy the
.dfm from Windows as well as the .xfm to Linux, maintaining both files. Otherwise,
the .dfm file will be modified on Linux and may no longer work on Windows. If you
plan to write cross-platform applications, the .xfm will work on Delphi editions that
support CLX.
15-18
Developer’ s Guide
Transferring applications between Windows and Linux
Environmental differences between Windows and Linux
Currently, cross-platform means an application that can compile virtually
unchanged on both the Windows and Linux operating systems. However, there are
many differences between Linux and the Windows operating environments.
Table 15.6 Differences in the Linux and Windows operating environments
Difference Description
File name case sensitivity In Linux, file names are case sensitive. The file Test.txt is not the same
file as test.txt. You need to pay close attention to capitalization of file
names on Linux.
Line ending characters On Windows, lines of text are terminated by CR/LF (that is, ASCII 13

+ ASCII 10), but on Linux it is LF. While the Code editor can handle
the difference, you should be aware of this when importing code from
Windows.
End of file character In MS-DOS and Windows, the character value #26 (
Ctrl
-
Z
) is treated as
the end of the text file, even if there is data in the file after that
character. Linux uses
Ctrl
+
D
as the end-of-file character.
Batch files/shell scripts The Linux equivalent of .bat files are shell scripts. A script is a text file
containing instructions, saved and made executable with the
command, chmod +x <scriptfile>. The scripting language depends on
the shell you are using on Linux. Bash is commonly used.
Command confirmation In MS-DOS or Windows, if you try to delete a file or folder, it asks for
confirmation (“Are you sure you want to do that?”). Generally, Linux
won't ask; it will just do it. This makes it easy to accidentally destroy a
file or the entire file system. There is no way to undo a deletion on
Linux unless a file is backed up on another media.
Command feedback If a command succeeds on Linux, it redisplays the command prompt
without a status message.
Command switches Linux uses a dash (-) to indicate command switches or a double dash
( ) for multiple character options where DOS uses a slash (/) or dash
(-).
Configuration files On Windows, configuration is done in the registry or in files such as
autoexec.bat.

On Linux, configuration files are created as hidden files in the user’s
home directory. Configuration files in the /etc directory are usually
not hidden files.
Linux also uses environment variables such as LD_LIBRARY_PATH
(search path for libraries). Other important environment variables:
• HOME Your home directory (/home/sam)
• TERM Terminal type (xterm, vt100, console)
• SHELL Path to your shell (/bin/bash)
• USER Your login name (sfuller)
• PATH List to search for programs
They are specified in the shell or in files such as .bashrc.
DLLs/Shared object files On Linux, you use shared object files (.so). In Windows, these are
dynamic link libraries (DLLs).
Developing cross-platform applications
15-19
Transferring applications between Windows and Linux
Drive letters Linux doesn't have drive letters. An example Linux pathname is
/lib/security. See DriveDelim in the runtime library.
Exceptions Operating system exceptions are called signals on Linux.
Executable files On Linux, executable files require no extension. On Windows,
executable files have an exe extension.
File name extensions Linux does not use file name extensions to identify file types or to
associate files with applications.
File permissions On Linux, files (and directories) are assigned read, write, and execute
permissions for the file owner, group, and others. For example,
-rwxr-xr-x means, from left to right:
• - is the file type (- = ordinary file, d = directory, l = link)
• rwx are the permissions for the file owner (read, write, execute)
• r-x are the permissions for the group of the file owner (read,
execute)

• r-x are the permissions for all other users (read, execute)
The root user (superuser) can override these permissions.
You need to make sure that your application runs under the correct
user and has proper access to required files.
Make utility Borland's make utility is not available on the Linux platform. Instead,
you can use Linux's GNU make utility.
Multitasking Linux fully supports multitasking. You can run several programs (in
Linux, called processes) at the same time. You can launch processes in
the background (using & after the command) and continue working
straight away. Linux also lets you have several sessions.
Pathnames Linux uses a forward slash (/) wherever DOS uses a backslash (\). A
PathDelim constant can be used to specify the appropriate character
for the platform. See PathDelim in the runtime library. See “Directory
structure on Linux” on page 15-20.
Search path When executing programs, Windows always checks the current
directory first, then looks at the PATH environment variable. Linux
never looks in the current directory but searches only the directories
listed in PATH. To run a program in the current directory, you
usually have to type ./ before it.
You can also modify your PATH to include ./ as the first path to
search.
Search path separator Windows uses the semicolon as a search path separator. Linux uses a
colon. See PathDelim in the runtime library.
Symbolic links On Linux, a symbolic link is a special file that points to another file on
disk. Place symbolic links in the global bin directory that points to
your application's main files and you don't have to modify the system
search path. A symbolic link is created with the ln (link) command.
Windows has shortcuts for the GUI desktop. To make a program
available at the command line, Windows install programs typically
modify the system search path.

Table 15.6 Differences in the Linux and Windows operating environments (continued)
Difference Description
15-20
Developer’ s Guide
Transferring applications between Windows and Linux
Registry
Linux does not use a registry to store configuration information. Instead, you use text
configuration files and environment variables rather than the registry. System
configuration files on Linux are often located in /etc, such as /etc/hosts. Other user
profiles are located in hidden files (preceded with a dot), such as .bashrc, which
holds bash shell settings or .XDefaults, which is used to set defaults for X programs.
Registry-dependent code may be changed to using a local configuration text file
instead. Settings that users can change must be saved in their home directory so that
they have permission to write to it. Configuration options that need to be set by the
root are stored in /etc. Writing a unit containing all the registry functions but
diverting all output to a local configuration file is one way you could handle a former
dependency on the registry.
To place information in a global location on Linux, you can store a global
configuration file in the /etc directory or the user’s home directory as a hidden file.
Therefore, all of your applications can access the same configuration file. However,
you must be sure that the file permissions and access rights are set up correctly.
You can also use .ini files in cross-platform applications. However, in CLX, you need
to use TMemIniFile instead of TRegIniFile.
Look and feel
The visual environment in Linux looks somewhat different than it does in Windows.
The look of dialogs may differ depending on which window manager you are using,
such as KDE or Gnome.
Directory structure on Linux
In Linux, any file or device can be mounted anywhere on the file system. Linux
pathnames use forward slashes whereas Windows pathnames use backslashes. The

initial slash stands for the root directory.
Following are some of the commonly used directories in Linux.
Table 15.7 Common Linux directories
Directory Contents
/ The root or top directory of the entire Linux file system
/root The root file system; the Superuser's home directory
/bin Commands, utilities
/sbin System utilities
/dev Devices shown as files
/lib Libraries
/home/username Files owned by the user where username is the user's login name.
/opt Optional
/boot Kernel that gets called when the system starts up
/etc Configuration files
Developing cross-platform applications
15-21
Cross-platform database applications
Note
Different distributions of Linux sometimes place files in different locations. A utility
program may be placed in /bin in a Red Hat distribution but in /usr/local/bin in a
Debian distribution.
Refer to www.pathname.com for additional details on the organization of the UNIX/
Linux hierarchical file system and to read the Filesystem Hierarchy Standard.
Cross-platform database applications
On Windows, you can access database information by using ADO, BDE, and
InterBase Express. However, these three choices are not available on Kylix. Instead,
on both Windows and Linux, you can use dbExpress, a cross-platform data access
technology, depending on which edition of Delphi you have.
Before you port a database application to dbExpress so that it will run on Linux, you
should understand the differences between using dbExpress and the data access

mechanism you were using. These differences occur at different levels.
• At the lowest level, there is a layer that communicates between your application
and the database server. This could be ADO, the BDE, or the InterBase client
software. This layer is replaced by dbExpress, which is a set of lightweight drivers
for dynamic SQL processing.
• The low-level data access is wrapped in a set of components that you add to data
modules or forms. These components include database connection components,
which represent the connection to a database server, and datasets, which represent
the data fetched from the server. Although there are some very important
differences, due to the unidirectional nature of dbExpress cursors, the differences
are less pronounced at this level, because datasets all share a common ancestor, as
do database connection components.
• At the user-interface level, there are the fewest differences. CLX data-aware
controls are designed to be as similar as possible to the corresponding Windows
controls. The major differences at the user interface level arise from changes
needed to accommodate the use of cached updates.
For information on porting existing database applications to dbExpress, see “Porting
database applications to Linux” on page 15-24. For information on designing new
dbExpress applications, see Chapter 19, “Designing database applications.”
/usr Applications, programs. Usually includes directories like /usr/spool, /usr/
man, /usr/include, /usr/local
/mnt Other media mounted on the system such as a CD or a floppy disk drive
/var Logs, messages, spool files
/proc Virtual file system and reporting system statistics
/tmp Temporary files
Table 15.7 Common Linux directories (continued)
Directory Contents

×