Resumo: Provides information to assist developers in getting up and running with the Delphi for .NET Compact Framework preview compiler.
Introduction
Borland have recently released a preview version of their latest
Delphi for .NET compiler, which allows Delphi developers to target the .NET
Compact Framework for the first time. This article is designed to assist developers in exploring the world of Compact Framework development
with the preview compiler.
Setting
up the Development Environment
The first step is to download the preview compiler from the Registered User Updates page, and to install it onto your development
system. For this article, the compiler and all support files have been
extracted to the 'C:\Program Files\Borland\3.0\CF Preview' directory.
As the preview compiler can not be invoked directly from the Delphi
2005 IDE, we will set up a batch file to assist us in compiling Compact Framework applications. The
batch file we will use looks like this:-
@echo off
rem **************************************************************
rem ** Batch file to be used from the Delphi 2005 IDE Tools menu
rem ** to invoke the Compact Framework Preview compiler. It takes
rem ** two parameters as follows:
rem ** %1 - Name of project .dpr file
rem ** %2 - Path to project directory
rem **************************************************************
set _DCCILPATH_="C:\Program Files\Borland\BDS\3.0\CFPreview\Bin\dccil.exe"
set _CFUNITS_="C:\Program Files\Borland\BDS\3.0\CFPreview\Lib"
set _PROJECTNAME_=%1
set _PROJECTDIR_=%2
rem *************************************************************
rem ** Ensure the Delphi 2005 Bin directory is in the path. It
rem ** may have been removed by a User path override.
rem *************************************************************
set _BDSDIR_=C:\Program Files\Borland\BDS\3.0\Bin
path %_BDSDIR_%;%PATH%
rem *************************************************************
rem ** Cater for the fact that paths with spaces can't be passed
rem ** in from the Tools menu
rem *************************************************************
SHIFT
SHIFT
:LOOP
IF "%1" == "" GOTO END
set _PROJECTDIR_=%_PROJECTDIR_% %1
SHIFT
GOTO LOOP
:END
cd %_PROJECTDIR_%
del *.dc?il
%_DCCILPATH_% "%_PROJECTDIR_%%_PROJECTNAME_%" -u%_CFUNITS_% -luSystem.Windows.Forms -luSystem.Data
pause
The batch file takes two command line parameters, with the first one being the file name of the project to compile, and the second one
being the path where the project resides. For the purpose of this article, only the System.Windows.Forms.dll assembly needs to be referenced,
but additional assemblies can be referenced by adding extra -lu parameters.
It caters for the fact that the Delphi 2005 directory may not be in the PATH variable accessible to the batch file when run within the context
of the IDE (this can be overridden). It also handles project paths that may contain spaces, as this information cannot currently be passed in as
one parameter from the built-in macros available when configuring an item on the IDE tools menu.
Once this batch file has been created, we can configure the IDE so it can be invoked for the current project from the Tools menu.
To do this, select the Configure Tools... option from the Tools menu, click the Add... button, and enter the following information:
Title: Delphi.NET CF Preview Compiler
Program: <Fully qualified path to batch file>
Parameters: $SAVEALL $NAMEONLY($PROJECT).dpr $PATH($PROJECT)
Below is an example of this:
Click the OK button, and you should now have a Delphi.NET CF Preview Compiler option at the end of the Delphi 2005 Tools menu. When invoked, it
will prompt for all changed files to be saved, and will call our batch file, passing in the Project dpr file name and full path information.
Configuring the Emulator
For those developers not lucky enough to own a Compact Framework
compatible device, an emulator will be required in order to test the
programs created with the compiler. This article will use the Microsoft
Windows CE 5.0 Device emulator, which is freely downloadable from
the Microsoft web site.
Marc Rohloff has already given detailed instructions on how to
configure the Microsoft Windows CE 5.0 Device emulator, in his Getting
Started with C# and the Compact Framework. With his kind
permission, this information has been reproduced below.
Before running the installation, make sure that you have an active
internet connection. If you have a slow connection and do not yet have MSXML
4.0 sp 2, installed it also helps to download and install this
first.
Once you have the emulator installed, make a copy of the menu
shortcut and modify it. You will want to add some command line options.
Below is an example of a valid command line for the emulator.:
|
Emulator_500.exe nk.cem
/vmid {6F5AE65B-98FF-46A9-A0E1-29B82C9779D4} /vmname "CE 5.0 (CF
1.0)" /sharedfolder c:\dev\net\cf /video 240x320x16 |
The emulator uses the GUID specified by the vmid
option to save the state of the device between sessions, while the sharedfolder
option makes your c:devnetcf
folder appear as a storage card on the emulated device. This makes it
much easier to share and copy files from your desktop.
|
Emulator
Tips and Tricks
If
you change the command line parameters then you will need to
delete the saved files from your My
Documents\My Virtual Machines folder for
the new parameters to take effect.
Occasionally
the emulator does not find the storage card when you start up. You
can fix this by performing a soft reset.
|
Emulating other Mobile
Devices
Additional emulator images can be downloaded from the Microsoft
website, and the CE 5.0 emulator can be configured to use these so other
devices can be emulated. For this article, we will create an application
that targets PocketPC devices running the Windows Mobile 2003 operating
system.
The Windows Mobile 2003 emulator images can be downloaded from the
Microsoft site. Once we have installed the images, we need to
change the shortcut for the CE 5.0 emulator to reference one of the new
emulator images. The nk.cem parameter in the
emulator command line specified earlier refers to the binary image that the
emulator loads. We will change this to reference one of the Windows Mobile
2003 emulator images we've installed. We will also use the /video
command line parameter to ensure the emulator is displayed using the
correct screen dimensions, and use the /sharedfolder parameter to specify a local directory which will be available on the
emulator. Our new command line looks like this:
|
"C:\DevTools\Windows CE
5.0 Emulator\Emulator_500.exe" "C:\DevTools\Windows CE
Tools\wce420\POCKET PC 2003\Emulation\PPC_2003_WWE.bin"
/sharedfolder c:\source\d2005\delphi\delphi.net\cf\shared /video
240x320x16 |
We can now use the shortcut to run a PocketPC Windows Mobile
2003 emulator, as shown below.
Installing the Compact
Framework
In order to link against the Compact Framework assemblies, it is necessary to have them installed on your development machine,
or to have a .dcpil file which the compiler can link against instead. Borland have provided .dcpil files for the more common
Compact Framework assemblies, but you may need to use a class in an assembly which doesn't have an existing .dcpil file. In this case you will need
the original assembly. If you don't already have the Compact Framework SDK installed, the assemblies will have
to be obtained from a device that already has them installed. Once again, this information was published in
Marc's
article, and with his permission has been reproduced below.
Many devices, including the CE Emulator, come with version 1.0 of
the Compact Framework installed. You can check the version on your device by
opening the Run
dialog and typing cgacutil.
If you have latest service pack (sp 2) installed the version should be 1.0.3316.0.
If you do not have the framework installed then you can download
the latest version from Microsoft's
mobility website. The end-user version comes with an automatic
installer but requires an ActiveSync connection.
If you do not have ActiveSync then you will need to download the
developer version of the CF Framework. Unpack it, copy the appropriate CAB
file to your device and open it from there to install it.
Copying the CF Assemblies
To be able to compile for the compact framework you need to have
the assemblies available on your desktop. You can copy them from your
compact device or emulator. Open the My
DeviceWindows folder, and make sure that all the hidden files
are visible. Find all the dlls
that that have names starting with "GAC_",
there should be 11 of them, and then copy them onto your PC via the Storage
Card. I copied mine to a folder called c:devnetcfassemblies.
Lastly, rename the files as shown in the table below.
|
Filename on
Compact Device |
Required
Filename |
|
GAC_mscorlib_v1_0_5000_0_cneutral_1 |
mscorlib |
|
GAC_System_v1_0_5000_0_cneutral_1 |
System |
|
GAC_System.Data_v1_0_5000_0_cneutral_1 |
System.Data |
|
GAC_System.Drawing_v1_0_5000_0_cneutral_1 |
System.Drawing |
|
GAC_System.Net.IrDA_v1_0_5000_0_cneutral_1 |
System.Net.IrDA |
|
GAC_System.Web.Services_v1_0_5000_0_cneutral_1 |
System.Web.Services |
|
GAC_System.Windows.Forms.DataGrid_v1_0_5000_0_cneutral_1 |
System.Windows.Forms.DataGrid |
|
GAC_System.Windows.Forms_v1_0_5000_0_cneutral_1 |
System.Windows.Forms |
|
GAC_System.Xml_v1_0_5000_0_cneutral_1 |
System.Xml |
|
GAC_Microsoft.WindowsCE.Forms_v1_0_5000_0_cneutral_1 |
Microsoft.WindowsCE.Forms |
|
GAC_Microsoft.VisualBasic_v7_0_5000_0_cneutral_1 |
Microsoft.VisualBasic |
Developing and running a
Delphi for .NET Application
We are now ready to create
our first Delphi for .NET Compact Framework application. Start up Delphi
2005, select File|New|Windows Forms Application -
Delphi
for .NET. Save the form unit as MainForm.pas, and the project file as
HelloWorld.dpr.
Switch to the form designer for MainForm and change the Name property to TMainForm. Drop on a Label from the Windows Forms category of the Tool Palette. Set the Label.Text
property to "Hello World!", and save the form. The code for MainForm looks
like this:-
unit MainForm;
interface
uses
System.Drawing, System.Collections, System.ComponentModel, System.Windows.Forms,
System.Data;
type
TMainForm = class(System.Windows.Forms.Form)
{$REGION 'Designer Managed Code'}
strict private
/// <summary>
/// Required designer variable.
/// </summary>
Components: System.ComponentModel.Container;
Label1: System.Windows.Forms.Label;
///<summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure InitializeComponent;
{$ENDREGION}
strict protected
/// <summary>
/// Clean up any resources being used.
/// </summary>
procedure Dispose(Disposing: Boolean); override;
private
{Private Declarations }
public
constructor Create;
end;
[assembly: RuntimeRequiredAttribute(TypeOf(TMainForm))]
implementation
{$AUTOBOX ON}
{$REGION 'Windows Form Designer generated code'}
/// <summary>
/// Required method for Designer support -- do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TMainForm.InitializeComponent;
begin
Self.Label1 := System.Windows.Forms.Label.Create;
Self.SuspendLayout;
//
// Label1
//
Self.Label1.Location := System.Drawing.Point.Create(16, 16);
Self.Label1.Name := 'Label1';
Self.Label1.TabIndex := 0;
Self.Label1.Text := 'Hello World!';
//
// TMainForm
//
Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13);
Self.ClientSize := System.Drawing.Size.Create(292, 266);
Self.Controls.Add(Self.Label1); Self.Name := 'TMainForm';
Self.Text := 'WinForm8';
Self.ResumeLayout(False);
end;
{$ENDREGION}
procedure TMainForm.Dispose(Disposing: Boolean);
begin
if Disposing then
begin
if Components <> nil then
Components.Dispose();
end;
inherited Dispose(Disposing);
end;
constructor TMainForm.Create;
begin
inherited Create;
//
// Required for Windows Form Designer support
//
InitializeComponent;
//
// TODO: Add any constructor code after InitializeComponent call
//
end;
end.
We will now configure our project so it will compile to the
directory shared with the emulator. We will also set the output directories for our .dcuil and .dcpil files so they will be placed in the app
Select Project|Options..., and click on the
Directories/Conditionals entry. Enter the path to the shared directory in the Output Directory: section, click OK, and save the project.
We are now ready to compile our first Compact Framework application. Select the Delphi CF Preview Compiler option from the Tools menu:

This will invoke the batch file we created earlier, after prompting for any changes to be saved. The output is shown below:

As you can see, the compilation failed with many Undeclared
identifier errors. Not all the methods and classes available
on the full .NET Framework have been implemented on the Compact Framework,
and because we used a WinForms designer targetting the full .NET
Framework, some properties specific only to that were generated in our InitializeComponent
section. Thankfully, the .NET Framework SDK documentation explicitly states
which methods and classes are available on the Compact Framework,
so dilligent referral to this is recommended, especially considering
not all instances will be picked up at compile time.
We will change the code to fix these errors and attempt
to compile the application again. Our new code for MainForm.pas
looks like this (I have also stripped out all the auto-generated comments
for brevity):
unit MainForm;
interface
uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data;
type
TMainForm = class(System.Windows.Forms.Form)
{$REGION 'Designer Managed Code'}
strict private
Components: System.ComponentModel.Container;
Label1: System.Windows.Forms.Label;
procedure InitializeComponent;
{$ENDREGION}
strict protected
procedure Dispose(Disposing: Boolean); override;
private
{Private Declarations }
public
constructor Create;
end;
implementation
{$AUTOBOX ON}
{$REGION 'Windows Form Designer generated code'}
procedure TMainForm.InitializeComponent;
begin
Self.Label1 := System.Windows.Forms.Label.Create;
//
// Label1
//
Self.Label1.Location := System.Drawing.Point.Create(16, 16);
Self.Label1.Text := 'Hello World!';
//
// TMainForm
//
Self.ClientSize := System.Drawing.Size.Create(292, 266);
Self.Controls.Add(Self.Label1);
end;
{$ENDREGION}
procedure TMainForm.Dispose(Disposing: Boolean);
begin
if Disposing then
begin
if Components <> nil then
Components.Dispose();
end;
inherited Dispose(Disposing);
end;
constructor TMainForm.Create;
begin
inherited Create;
InitializeComponent;
end;
end.
To resolve the File not found:
'MainForm.TMainForm.resources' error, we need to remove the
MainForm.resx file from the project. To do that, select Project|Remove from
Project..., click on the MainForm.resx line in the
listview, and click the OK button. And although the error wasn't reported
in our initial compile attempt, we will also need to remove the [STAThread]
attribute from the project source. Once these changes are made, save all
files and invoke the batch file again.
This time the compilation was successful, so we should now be able
to see our results on the emulator. It should have been compiled to, and be
visible from, a storage card on the emulator. To navigate to this, click the
Start button on the emulator, select Programs, and click on the File Explorer icon. By
default, this will place us in the My Documents folder.
In order to get to the storage card, click the drop down arrow next to the
My Documents text at the top of the screen, and select My Device
Click on the Storage Card folder, and you should see two entries
called HelloWorld. The top one will be HelloWorld.exe, and the bottom one will be HelloWorld.pdb (a debug file generated by the compiler). Click on the
HelloWorld.exe entry, and the application should run.
Take a moment to marvel at our handywork, then click the X in the
titlebar to close the application (or did it? More on that in a minute)
We will now change the application to add a Button which will
change the caption of a label when clicked. Our new code is as follows:
unit MainForm;
interface
uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data;
type
TMainForm = class(System.Windows.Forms.Form)
{$REGION 'Designer Managed Code'}
strict private
Components: System.ComponentModel.Container;
Label1: System.Windows.Forms.Label;
Button1: System.Windows.Forms.Button;
Label2: System.Windows.Forms.Label;
procedure InitializeComponent;
procedure Button1_Click(sender: System.Object; e: System.EventArgs);
{$ENDREGION}
strict protected
procedure Dispose(Disposing: Boolean); override;
private
{ Private Declarations }
public
constructor Create;
end;
implementation
{$AUTOBOX ON}
{$REGION 'Windows Form Designer generated code'}
procedure TMainForm.InitializeComponent;
begin
Self.Label1 := System.Windows.Forms.Label.Create;
Self.Button1 := System.Windows.Forms.Button.Create;
Self.Label2 := System.Windows.Forms.Label.Create;
//
// Label1
//
Self.Label1.Location := System.Drawing.Point.Create(16, 16);
Self.Label1.Text := 'Hello World!';
//
// Button1
//
Self.Button1.Location := System.Drawing.Point.Create(16, 40);
Self.Button1.Text := 'Click Me!';
Include(Self.Button1.Click, Self.Button1_Click);
//
// Label2
//
Self.Label2.Location := System.Drawing.Point.Create(16, 72);
Self.Label2.Size := System.Drawing.Size.Create(152, 23);
//
// TMainForm
//
Self.ClientSize := System.Drawing.Size.Create(292, 266);
Self.Controls.Add(Self.Label2);
Self.Controls.Add(Self.Button1);
Self.Controls.Add(Self.Label1);
end;
{$ENDREGION}
procedure TMainForm.Dispose(Disposing: Boolean);
begin
if Disposing then
begin
if Components <> nil then
Components.Dispose();
end;
inherited Dispose(Disposing);
end;
constructor TMainForm.Create;
begin
inherited Create;
InitializeComponent;
end;
procedure TMainForm.Button1_Click(sender: System.Object; e: System.EventArgs);
begin
Label2.Text := 'Delphi is in the building!';
end;
end.
Invoke the batch file from the Tools menu to compile the code
As you can see from the above output, the exe couldn't be
overwritten because it is currently in use. This is because of a feature introduced with Pocket PC 2002 called Smart Minimize. By default on
devices running Pocket PC 2002 and above, when the user clicks the X in an applications main form titlebar
it doesn't close the application, but instead minimizes to the background. If the
application is invoked again (via a shortcut or clicking on it in the File
Explorer), it is brought back to the foreground.
Our HelloWorld application can be unloaded from memory by accessing
the Memory section of the PocketPC system settings, but for simplicity now
we will simply shutdown and restart the emulator. This can be achieved by selecting Shut Down... from the Emulator menu, selecting Turn off, and clicking the OK
button.
Restart the emulator, and our application can once again be compiled to the Storage Card directory.
We will now also change our code to add a Close button, so the
application can be terminated normally. Another approach would be to disable the Smart Minimize behaviour by setting the WinForm.MinimizeBox property to False.
This would change the X button to an OK button, which when clicked would close the application. Below is our updated code:-
unit MainForm;
interface
uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data;
type
TMainForm = class(System.Windows.Forms.Form)
{$REGION 'Designer Managed Code'}
strict private
Components: System.ComponentModel.Container;
Label1: System.Windows.Forms.Label;
Button1: System.Windows.Forms.Button;
Button2: System.Windows.Forms.Button;
Label2: System.Windows.Forms.Label;
procedure InitializeComponent;
procedure Button1_Click(sender: System.Object; e: System.EventArgs);
procedure Button2_Click(sender: System.Object; e: System.EventArgs);
{$ENDREGION}
strict protected
procedure Dispose(Disposing: Boolean); override;
private
{ Private Declarations }
public
constructor Create;
end;
implementation
{$AUTOBOX ON}
{$REGION 'Windows Form Designer generated code'}
procedure TMainForm.InitializeComponent;
begin
Self.Label1 := System.Windows.Forms.Label.Create;
Self.Button1 := System.Windows.Forms.Button.Create;
Self.Button2 := System.Windows.Forms.Button.Create;
Self.Label2 := System.Windows.Forms.Label.Create;
//
// Label1
//
Self.Label1.Location := System.Drawing.Point.Create(16, 16);
Self.Label1.Text := 'Hello World!';
//
// Button1
//
Self.Button1.Location := System.Drawing.Point.Create(16, 40);
Self.Button1.Text := 'Click Me!';
Include(Self.Button1.Click, Self.Button1_Click);
//
// Button2
//
Self.Button2.Location := System.Drawing.Point.Create(152, 224);
Self.Button2.Text := 'Close';
Include(Self.Button2.Click, Self.Button2_Click);
//
// Label2
//
Self.Label2.Location := System.Drawing.Point.Create(16, 72);
Self.Label2.Size := System.Drawing.Size.Create(152, 23);
//
// TMainForm
//
Self.ClientSize := System.Drawing.Size.Create(292, 266);
Self.Controls.Add(Self.Label2);
Self.Controls.Add(Self.Button2);
Self.Controls.Add(Self.Button1);
Self.Controls.Add(Self.Label1);
end;
{$ENDREGION}
procedure TMainForm.Dispose(Disposing: Boolean);
begin
if Disposing then
begin
if Components <> nil then
Components.Dispose();
end;
inherited Dispose(Disposing);
end;
constructor TMainForm.Create;
begin
inherited Create;
InitializeComponent;
end;
procedure TMainForm.Button1_Click(sender: System.Object; e: System.EventArgs);
begin
Label2.Text := 'Delphi is in the building!';
end;
procedure TMainForm.Button2_Click(sender: System.Object; e: System.EventArgs);
begin
Close;
end;
end.
Compiling and running the application, and clicking on the Click Me! button
yields the following output:
And below is an image of the same application running on an actual
Compaq iPaq PocketPC device:
Summary
With the delivery of the Delphi for .NET preview compiler, Borland
has given Delphi developers the ability to target the Compact Framework
for the first time. This article has hopefully provided some guidance to
allow developers to start exploring what will be for many a new and
exciting world.
Acknowledgements
Thanks to Marc Rohloff for the permission to use excerpts from his
Getting Started with C# and the Compact Framework article.
Also thanks to Marc and John Kaster for assisting with some of the technical aspects of this article. And of course,
thanks to Seppy Bloom, Danny Thorpe, Tagawa-san, and all the other R & D engineers who made this article possible in the first place by creating the preview compiler.
Connect with Us