Borland Delphi 2005 Migration To .NET Using VCL For
Borland Delphi 2005 Migration To .NET Using VCL For
Brazil
Case Study
Product News
Events
Training
Delphi 2005
Borland Delphi 2005 Migration to .NET using VCL for .NET
by Bob Swart, Bob Swart Training & Consultancy
Abstract - This tutorial demonstrates the migration of Delphi Win32 source code, units and (database) applications to the
Microsoft .NET Framework using Borland Delphi 2005 and VCL (for .NET).
Introduction
VCL and VCL for .NET
Data Access
Summary and Conclusions
Introduction
In this tutorial we will migrate a real-world Win32 application to the Microsoft .NET Framework using Delphi 2005, using the Borland VCL
(Visual Component Library) as the framework. A number of existing VCL for Win32 applications - taken from the Delphi 7 Demos
directory - will be opened in Delphi 2005 and migrated to a .NET target using VCL for .NET.
These exercises will demonstrate several migration issues, small and more significant alike.
VCL and VCL for .NET
The VCL has been made available for the .NET Framework, enabling us to easily migrate Win32 VCL applications to .NET (its also
possible to take VCL projects to WinForms).
Delphi 2005 comes with a large number of example applications, in the BDS\3.0\Demos directory, which contains - among others - the
Delphi.NET and DelphiWin32 subdirectories. The BDS\3.0\DelphiWin32\VCLWin32\ directory contains several Win32 VCL examples,
some of which are already migrated to .NET, and found in the BDS\3.0\Delphi.NET\VCL directory.
One of the examples which is not already migrated to .NET is the Threads example, demonstrating the QuickSort, SelectionSort and
BubbleSort algorithms in a multi-threaded example. The Threads project is a Win32 VCL application that we will be migrating to .NET
using VCL for .NET.
First, let's create a copy of the necessary files.
Create a new subdirectory Threads in the BDS\3.0\Demos\Delphi.NET\VCL directory. The result of our migration will then be
available as another example of a Delphi for .NET VCL project.
Copy all files from the BDS\3.0\Demos\DelphiWin32\VCLWin32\Threads directory to the BDS\3.0\Demos\Delphi.NET\VCL
\Threads directory.
Remove the thrddemo.bdsproj file, since that file stores the fact that this was a Delphi Win32 project (and we want to migrate to .
NET instead).
Tutorial 1
Now we are ready to work on the new Threads project, and migrate it to .NET.
Since this project has no .bdsproj file associated with it, the Delphi 2005 IDE needs to ask you if you want to upgrade it to a Win32 or .
NET project. This is done with the Project Upgrade dialog, shown in the following figure:
Specify the Delphi for .NET target, and click on the OK button.
This will generate a thrddemo.bdsproj for us, with the .NET personality specified inside. We will now save the project, so the new
personality information is stored in the thrddemo.bdsproj file.
Do File | Save All, so the thrddemo project is saved, including the new thrddemo.bdsproj file.
Press Ctrl+F9 to compile the thrddemo project for the first time.
This should give you about 11 warnings and 5 errors, which are as follows:
[Warning] thrddemo.dpr(8): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] ThSort.pas(6): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
[Warning] ThSort.pas(7): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Warning] ThSort.pas(7): W1005 Unit 'Borland.Vcl.StdCtrls' is specific to a platform
[Warning] SortThds.pas(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] SortThds.pas(6): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Error] SortThds.pas(18): E2397 Unsafe pointer only allowed if compiling with {$UNSAFECODE ON}
[Error] SortThds.pas(57): E2003 Undeclared identifier: 'Point'
[Error] SortThds.pas(65): E2396 Unsafe code only allowed in unsafe procedure
[Error] SortThds.pas(107): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'
We can ignore all warnings for now, and will get back to those later. First, let's fix the compiler errors.
The first error is regarding line 18 of SortThds.pas, and mentions that "unsafe pointer only allowed if compiling with {$UNSAFECODE
ON}". The actual line of code that causes this warning is the declaration of FSortArray of type PSortArray in the TSortThread class
http://www.borland.com/delphi/demo/tutorial/tutorial1.html (2 of 20)3/27/2005 12:52:22 AM
Tutorial 1
definition:
type
PSortArray = ^TSortArray;
TSortArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
TSortThread = class(TThread)
private
FBox: TPaintBox;
FSortArray: PSortArray;
The PSortArray is a pointer to TSortArray, and a pointer is not a "safe" type, hence the warning. The warning is also followed by a
number of other unsafe warnings, related to the use of this unsafe pointer type.
Although the final result will have no unsafe types or code at all, at first it's usually easier to remove the compiler errors by marking code
as unsafe first - first make the project compile successfully, and then replace the unsafe sections by safe code.
Add the {$UNSAFECODE ON} compiler directive before the class definition for TSortThread, so the field declaration of
FSortArray is accepted.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Place the cursor in one of the Point identifiers in the source line in the Code Editor, and right click to select the Find Unit
submenu of the Refactor menu (alternately you can use the Refactor menu choice to select the Find Unit choice).
This will bring up the Find Unit dialog with the Search criteria Point already specified. A number of units are also mentioned, including
Borland.Vcl.Types.Point which seems like the perfect candidate for a definition of Point.
Select the Borland.Vcl.Types.Point unit, and click on either the Interface or Implementation choice to decide where this unit will
be added to the uses clause of the SortThds.pas unit.
Tutorial 1
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This will now result in 3 errors. As always, the last (fatal) error is caused by the fact that we have two earlier errors. So there are in fact
only two errors to fix.
[Error] SortThds.pas(70): E2396 Unsafe code only allowed in unsafe procedure
[Error] SortThds.pas(112): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'
We still use the unsafe pointer in FSortArray, and this is what the two errors report. The first error concerns a line of code in the Create
constructor, where we take the address of the SortArray parameter and assign it to the unsafe FSortArray pointer. This code is unsafe,
and doesn't compile unless we mark the Create constructor with the unsafe keyword.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This time, the error message about the unsafe code in the Create constructor is no longer shown. However, another error message
concerning the Create constructor now appears:
[Error] SortThds.pas(72): E2305 'Self' might not have been initialized
[Error] SortThds.pas(112): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'
The error message concerns the fact that we can call the inherited constructor after we've done some specific property initialization.
However, unless you have a good reason not to do so, the recommendation is to call the inherited constructor before the custom
constructor code. This is easy to fix, of course.
Move the inherited call to Create as first line of code in the Create constructor, as follows:
constructor TSortThread.Create(Box: TPaintBox; var SortArray: array of Integer); unsafe;
begin
Tutorial 1
inherited Create(False);
FBox := Box;
FSortArray := @SortArray;
FSize := High(SortArray) - Low(SortArray) + 1;
FreeOnTerminate := True;
end;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
We are now left with only one error to fix, again an unsafe code error message:
[Error] SortThds.pas(112): E2396 Unsafe code only allowed in unsafe procedure
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'
This time, it's the Execute method where we use the ^ operator on the unsafe pointer FSortArray. The fix consists of adding the unsafe
keyword to this method as well.
Add the unsafe keyword to the implementation of the Execute method, as follows:
procedure TSortThread.Execute; unsafe;
begin
Sort(Slice(FSortArray^, FSize));
end;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
[Error] SortThds.pas(114): E2454 Slice standard function not allowed for VAR nor OUT argument
[Fatal Error] ThSort.pas(39): F2063 Could not compile used unit 'SortThds.pas'
This is a bigger problem. For some reason, the Slice function under .NET has a problem with the way we pass the arguments right now.
Considering what it does, it actually looks safe to ignore the call to Slice, and just pass the actual FSortArray^ to Sort. Within the Sort
method, we'll use High and Low to determine the actual size of the array, and that should work just fine (note that we'll turn it into safe,
managed code in a moment anyway).
Remove the call to Sort that uses the Slice standard function, and replace it with a call to Sort passing just FSortArray^ as
argument, as follows:
procedure TSortThread.Execute; unsafe;
begin
// Sort(Slice(FSortArray^, FSize));
Sort(FSortArray^);
end;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
[Warning]
[Warning]
[Warning]
[Warning]
Tutorial 1
Remove the {$UNSAFECODE ON} compiler directive, as well as the two unsafe keywords (for the Create constructor and the
Execute method), and get ready to fix the unsafe code sections.
The first problem - causing all other problems - is the pointer type definition. We can replace the TSortArray definition by just an "array of
integer". If you want to keep code which can be compiled by the Win32 as well as the .NET compiler, you may want to use compiler
directives to distinguish between the original code and the new code.
Change the type definition of TSortArray to an array of integer, and use compiler directives for the old WIN32 and the new .NET
definition, as follows:
{$IFDEF WIN32}
PSortArray = ^TSortArray;
TSortArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
{$ELSE}
TSortArray = array of Integer;
{$ENDIF}
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This time, you'll get an error message about the definition of FSortArray, since PSortArray is an unknown type now. Using the .NET
compiler, we can simply define FSortArray as being of type TSortArray.
Tutorial 1
Change the type of field FSortArray from PSortArray to TSortArray. If you want to use compiler directives for WIN32 vs. .NET
code, this will be as follows:
TSortThread = class(TThread)
private
FBox: TPaintBox;
FSortArray: {$IFDEF WIN32}PSortArray{$ELSE}TSortArray{$ENDIF};
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This time, you'll get an error message in the create constructor about the @ operator which should not be used here.
Remove the use of the @ operator in the Create constructor. Using compiler directives, this can be done as follows:
constructor TSortThread.Create(Box: TPaintBox; var SortArray: array of Integer);
begin
inherited Create(False);
FBox := Box;
FSortArray := {$IFDEF WIN32}@{$ENDIF}SortArray;
FSize := High(SortArray) - Low(SortArray) + 1;
FreeOnTerminate := True;
end;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
The last error is about the use of the ^ operator in the Execute method. Obviously, you can again eliminate that one when using the .
NET compiler, changing it as follows:
procedure TSortThread.Execute;
begin
// Sort(Slice(FSortArray^, FSize));
Sort(FSortArray{$IFDEF WIN32}^{$ENDIF});
end;
*Note that Sort is taking a var argument, so don't worry about passing the entire array of integer here as value argument (otherwise it
would make sense to see if you could add a const keyword).
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
We only have the platform specific warnings left, no unsafe code errors anymore. This is now a native, safe, managed .NET executable,
using VCL for .NET. The Threads demo illustrated some points about quick-and-dirty (but unsafe) migration, followed by a full safe and
managed migration path from Win32 to .NET for Delphi VCL applications.
Data Access
Now that we've migrated a VCL application to .NET, it's time to move on to a bigger application, with some more real-world
characteristics. This includes data access, so let's take a look in the Delphi7\Demos\Db directory. There are several example
applications here, MastApp and IBMastApp the biggest, with the largest number of units and forms.
If you don't have Delphi 7, then just take a look at the BDS\3.0\Demos\DelphiWin32\Db directory, which also features the MastApp and
IBMastApp projects (but already migrated to the new project format - including a .bdsproj file).
The MastApp has been migrated to .NET, and can be found in the BDS\3.0\Demos\Delphi.NET\DB\MastApp directory, but the
IBMastApp project has not been migrated to VCL for .NET yet, and is absent from the BDS\3.0\Demos\Delphi.NET\DB or BDS\3.0
\Demos\Delphi.NET\VCL\Db directory.
So, as our main example, let's migrate the IBMastApp application from Win32 to .NET - a non-trivial database example application.
Tutorial 1
Create a new subdirectory IBMastApp in the BDS\3.0\Demos\Delphi.NET\VCL\Db directory. The result of our migration will then
be available as another example of a Delphi for .NET VCL DB project.
Copy all files from the BDS\3.0\Demos\DelphiWin32\VCLWin32\Db\IBMastApp directory to the BDS\3.0\Demos\Delphi.NET\VCL
\Db\IBMastApp directory.
Remove the mastapp.bdsproj file, since that file stores the fact that this was a Delphi Win32 project (and we want to migrate to .
NET instead).
Now we are ready to work on the new IBMastApp project, and migrate it to .NET.
Since this project has no .bdsproj file associated with it, the Delphi 2005 IDE needs to ask you if you want to upgrade it to a Win32 or .
NET project. This is done with the Project Upgrade dialog, shown in the following figure:
Specify the Delphi for .NET target, and click on the OK button.
This will generate a mastapp.bdsproj for us, with the .NET personality specified inside. We will now save the project, so the new
personality information is stored in the mastapp.bdsproj file.
Do File | Save All, so the mastapp project is saved, including the new mastapp.bdsproj file.
Open the data module, which is located in DataMod.pas, by double-clicking on the DataMod.pas node in the Project Manager.
The data module is designed as shown in the following screenshot, using InterBase Express as data access technology.
Tutorial 1
Click on the Database component (which is of type TIBDatabase) on the data module.
Right-click on the Database component, this will display a pop-up menu that tells you the version of InterBaseExpress (9.09)
and offers a choice for the Database Editor. Select the Database Editor, which will give you the following dialog:
Click on the Test button to verify that a connection to the InterBase database mastsql.gdb can be made. If not, make sure that
mastsql.gdb can be found at the specified location, and that InterBase itself is actually running.
Once you get a "Successful Connection" when you click on the Test button, you can close the Database Component Editor.
Tutorial 1
*Note that you will probably need to do this for every VCL project that you want to migrate to .NET: first make sure that the data access
components on the data module point to the right database. And while most VCL data access components have a VCL for .NET
counterpart, there is no support for SQL Links in .NET, so you may have to migrate those projects to dbExpress, dbGo for ADO,
InterBaseExpress or some other VCL for .NET data access technology.
Migrating Source Code
Once the data module and especially the data access connections have been verified, we can start to compile the project for the first
time.
This should give you about 17 warnings and 1 error, which are as follows:
[Warning] mastapp.dpr(23): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
[Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
[Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] MAIN.PAS(6): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
[Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
[Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Buttons' is specific to a platform
[Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.StdCtrls' is specific to a platform
[Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.Menus' is specific to a platform
[Warning] MAIN.PAS(7): W1005 Unit 'Borland.Vcl.ExtCtrls' is specific to a platform
[Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Windows' is specific to a platform
[Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Messages' is specific to a platform
[Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Graphics' is specific to a platform
[Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Controls' is specific to a platform
[Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Forms' is specific to a platform
[Warning] DataMod.pas(8): W1005 Unit 'Borland.Vcl.Dialogs' is specific to a platform
[Fatal Error] DataMod.pas(9): F1026 File not found: 'VarUtils.dcuil'
The warnings can be ignored - especially since they are only warnings to tell us that we are using VCL for .NET units that are specific to
a platform. To avoid these platform specific warnings, you can disable them if you wish.
Do Project | Options to go to the Project Options. In the Compiler Messages category, you can uncheck the "Platform Unit"
warning (as can be seen in the following screenshot). If you then rebuild the project, you will not get these warnings again.
Tutorial 1
Do Project | Build mastapp, or hit Shift+F9 to do a Build. This should no longer list the 17 warnings, but still the error.
Remove VarUtils from the uses clause of the interface section of DataMod.pas.
*Note that if you want your project to be compilable to a Win32 target as well, you may want to place the VarUtils unit in an {$IFDEF
WIN32} .... {$ENDIF} block instead of just removing the unit from the uses clause.
If you decide to use the IFDEF solution, modify the uses clause so it looks as follows:
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
DB, IBQuery, IBCustomDataSet, IBTable, IBDatabase, IB, Variants
{$IFDEF WIN32}, VarUtils {$ENDIF};
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Tutorial 1
The error message is about the CustNo argument to the MastData.Cust.Locate. It's of type Double, but a Variant is expected. That
should be no problem, but the compiler needs to have the Variants unit added to the uses clause.
Add the Variants unit to the uses clause of the implementation section of unit Edcust.pas.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Remove the DBLookup unit from the uses clauses of the interface section of Edorders.pas.
*Note that if you want your project to be compilable to a Win32 target as well, you may want to place the DBLookup unit in an {$IFDEF
WIN32} .... {$ENDIF} block instead of just removing the unit from the uses clause.
If you decide to use the IFDEF solution, modify the uses clause so it looks as follows:
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Dialogs, Forms, StdCtrls, DBGrids, DBCtrls, DB,
Buttons, Grids, {$IFDEF WIN32} DBLookup, {$ENDIF} ExtCtrls, Mask;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
types: 'Variant'
types: 'Variant'
types: 'Variant'
not compile used
and 'Double'
and 'Double'
and 'TCaption'
unit 'SrchDlg.pas'
The first three problems are very similar to an error that we saw before, which could simply be solved by adding the Variants unit to the
uses clause.
Add the Variants unit to the uses clause of the implementation section of unit SrchDlg.pas.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Add the Variants unit to the uses clause of the implementation section of unit Edorders.pas.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Add the Variants unit to the uses clause of the implementation section of unit BrCstOrd.pas.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Tutorial 1
Remove DBLookup from uses clause (interface) of Edparts.pas, or place the DBLookup unit in an {$IFDEF WIN32} block as
follows:
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, DB, StdCtrls, ExtCtrls, Mask, DBCtrls,
{$IFDEF WIN32} DBLookup, {$ENDIF} Buttons;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Add the Variants unit to the uses clause of the implementation section of unit Edparts.pas.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Add the Variants unit to the uses clause of the implementation section of unit Brparts.pas.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
If you are running the updated version of Delphi 2005, then your application will compile and link at this time and you can move on to the
section "Running the Marine Adventure Order Entry Application". If you find that you still have some errors, then please continue on
here.
This will result in 3 hints, 1 warning, and 1 fatal error.
[Hint] DataMod.pas(244): H2443 Inline function 'ExpandFileName' has not been expanded
because unit 'System.IO' is not specified in USES list
[Hint] DataMod.pas(743): H2443 Inline function 'FileExists' has not been expanded because
unit 'System.IO' is not specified in USES list
[Hint] DataMod.pas(748): H2443 Inline function 'ExtractFileName' has not been expanded
because unit 'System.IO' is not specified in USES list
[Warning] EDORDERS.PAS(229): W1050 WideChar reduced to byte char in set expressions
[Fatal Error] CustRpt.pas(6): F1026 File not found: 'Quickrpt.dcuil'
At this time, you will also get a design-time error dialog that mentions properties which cannot be found when the Delphi 2005 VCL
Designer tries to display the CustRpt unit.
No QuickReports
The problems are caused by the fact that the Quickrpt.dcuil unit cannot be found by the CustRpt.pas unit: QuickReport for .NET is not
included with Delphi 2005. The recommended way to migrate this functionality, is to use Rave Reports for example. Or look for a .NET
version of QuickReports, or find some other reporting framework to use.
Reporting is left as exercise for the reader, but we still need to make the project compile - even without the reporting functionality.
Do Project | View Source to open the project source file mastapp.dpr, and look for the QuickReports units in the uses clause
(these are the lines with the TQuickRep types), and place them in comments as follows:
uses
Forms,
Main in 'MAIN.PAS' {MainForm},
Brparts in 'BRPARTS.PAS' {BrPartsForm},
QryCust in 'QryCust.pas' {QueryCustDlg},
Tutorial 1
Move to the bottom of the project source file, and locate the three CreateForm statements that create the QuickReports forms.
Select them in a block, and press Ctrl+/ to place them all in comments, resulting in the following code:
begin
Application.Initialize;
SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update;
Application.Title := 'Marine Adventures Order Entry';
Application.HelpFile := 'MASTAPP.HLP';
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TBrPartsForm, BrPartsForm);
Application.CreateForm(TQueryCustDlg, QueryCustDlg);
Application.CreateForm(TEdPartsForm, EdPartsForm);
Application.CreateForm(TBrCustOrdForm, BrCustOrdForm);
Application.CreateForm(TEdCustForm, EdCustForm);
Application.CreateForm(TEdOrderForm, EdOrderForm);
Application.CreateForm(TSearchDlg, SearchDlg);
Application.CreateForm(TBrDateForm, BrDateForm);
Application.CreateForm(TAboutBox, AboutBox);
Application.CreateForm(TPickRpt, PickRpt);
// Application.CreateForm(TCustomerByInvoiceReport, CustomerByInvoiceReport);
// Application.CreateForm(TOrdersByDateReport, OrdersByDateReport);
// Application.CreateForm(TInvoiceByOrderNoReport, InvoiceByOrderNoReport);
Application.CreateForm(TPickOrderNoDlg, PickOrderNoDlg);
Application.CreateForm(TMastData, MastData);
SplashForm.Hide;
SplashForm.Free;
Application.Run;
end.
This is not enough, however, since the units that use QuickReports are also used in other places of the application. We need to find and
comment all of these.
Do Search | Find in Files, and look for CustRpt (which could be in the uses clause of some other units, and should then be
removed).
Tutorial 1
Open file Main.pas, and take a look at the uses clause of the implementation section, which includes the CustRpt unit.
*Note that Error Insight automatically marks this unit, as well as the OrderRpt and InvcRpt units as being invalid (the compiler cannot
resolve the unit names).
Use Ctrl+/ to place the CustRpt, OrderRpt, and InvcRpt units in comments.
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Select the code inside the PrintCustomerReport method and place it in comments, for example as follows (feel free to select
more or less code to comment):
procedure TMainForm.PrintCustomerReport(Preview: Boolean);
begin
Tutorial 1
with MastData.CustByLastInvQuery do
begin
Open;
//
if Preview then
//
CustomerByInvoiceReport.Preview
//
else
//
CustomerByInvoiceReport.Print;
Close;
end;
end;
The next problem can be found in the PrintOrderReport method, which again should be placed in comments.
Select the code inside the PrintOrderReport method, and press Ctrl+/ to put everything in comments, as follows:
PrintOrderReport in comments
There's one place left: the PrintInvoiceReport.
Select the code inside the PrintInvoiceReport method and place it in comments, for example as follows (feel free to select more
or less code to comment):
procedure TMainForm.PrintInvoiceReport(Preview: Boolean);
begin
if PickOrderNoDlg.ShowModal = mrOk then
//
if Preview then
//
InvoiceByOrderNoReport.Preview
//
else
Tutorial 1
//
end;
InvoiceByOrderNoReport.Print;
Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
Edit the datamod.pas unit, and locate the MastDataCreate method. Make sure to assignment DataFile with the value of
Database.DatabaseName, overwriting the value of the DataDirectory, as follows:
procedure TMastData.MastDataCreate(Sender: TObject);
var
DataFile: string;
begin
DataFile := DataDirectory + 'MASTSQL.GDB';
DataFile := Database.DatabaseName; // already working at design-time!
if not FileExists(DataFile) then
if MessageDlg('Could not locate MASTSQL.GDB. Would you like to locate the file?',
mtError, [mbYes, mbNo], 0) = mrYes then
if OpenDialog.Execute then
begin
if UpperCase(ExtractFileName(OpenDialog.FileName)) = 'MASTSQL.GDB' then
DataFile := OpenDialog.FileName
else
raise Exception.Create('Invalid File: ' + OpenDialog.FileName);
end
else
raise Exception.Create('Cannot locate Interbase data file: MASTSQL.GDB');
Database.DatabaseName := DataFile;
Database.Open;
Transaction.StartTransaction;
end;
*Note that you can also remove the call to DataDirectory here, but you still need to assign the new value to DataFile.
Tutorial 1
The project again compiles and runs, showing the Marine Adventures Order Entry application, as follows:
Order Form
Close the Order Form and Click on the Browse button for the Orders by Customer Form:
Tutorial 1
Close the Orders by Customer Form and Click on the Parts button for the Browse Parts Form:
Close the Browse Parts Form and if you are not running on an updated Delphi 2005, click on the Reports button for the Report
Selection Form:
Tutorial 1
The amount of effort that it takes in migrating VCL applications from Win32 to .NET is far less than it would take to rebuild the
application. Delphi 2005 offers great support for migration to .NET, protecting our investments of existing Win32 applications.