Applications that contain unsafe code will fail when you check them with PEVerify. This is a situation that you can accept as an intermediate migration result, but you may want to strive for a 100% safe version of your .NET application as end goal.
- 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:
- 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.
- 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:
- 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:
- 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:
*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.
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.
First, let's create a copy of the necessary files.
- 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.
- Start Delphi 2005
- Click on the Open Project button in the Welcome Page and open the mastapp.dpr project file from the BDS\3.0\Demos\Delphi.NET\VCL\Db\IBMastApp directory (the copy we just made of the Win32 demo).
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:

Project Upgrade mastapp to .NET
- 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.
Migrating Data Module
Now that we have associated the Delphi for .NET personality with this project, we first need to make sure that the database is pointing to the right location. This should be done before your first attempt to compile the application. Once the database connection is configured right, we can focus on the source code migration.
- 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.

VCL for .NET Data Module at design-time
We need to reconfigure the Database component, which can be located in the lower-right corner of the data module.
- 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:

Database Component Editor
Note the D:\ here in the path location. You may have to change that to C:\ and use Common Files instead of Borland to make InterBase connect to this database. For my default installation, the mastsql.gdb is found at C:\Program Files\Common Files\Borland Shared\Data\mastsql.gdb - your configuration may differ.
- 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.
*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.
- Press Shift+F2 to Save All files in the project.
- Press Ctrl+F9 to compile the mastapp 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.

Project Options -Warning Messages
- Do Project | Build mastapp, or hit Shift+F9 to do a Build. This should no longer list the 17 warnings, but still the error.
[Fatal Error] DataMod.pas(9): F1026 File not found: 'VarUtils.dcuil'
This error is caused by the fact that in VCL for .NET, the VarUtils unit is no longer available (most likely integrated in the Variants unit). So we can remove the no-longer-existent VarUtils unit from the uses clause.
- 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
, VarUtils ;
- Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This will result in 3 hints and 2 errors.
[Error] EDCUST.PAS(54): E2010 Incompatible types: 'Variant' and 'Double'
[Fatal Error] BrCstOrd.pas(48): F2063 Could not compile used unit 'EDCUST.PAS'
The offending routine that contains the source causing the incompatible type warning is as follows:
procedure TEdCustForm.Edit(CustNo: Double);
begin
MastData.Cust.Open;
MastData.Cust.Locate('CustNo', CustNo, []);
ShowModal;
end;
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.
This will result in 3 hints and 1 error.
[Fatal Error] EDORDERS.PAS(10): F1026 File not found: 'DBLookup.dcuil'
It appears that the DBLookup unit is also no longer available in VCL for .NET - or required for this project. We can safely remove it.
- 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, DBLookup, ExtCtrls, Mask;
- Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This will result in 3 hints and 4 errors.
[Error] SrchDlg.pas(54): E2010 Incompatible types: 'Variant' and 'Double'
[Error] SrchDlg.pas(64): E2010 Incompatible types: 'Variant' and 'Double'
[Error] SrchDlg.pas(98): E2010 Incompatible types: 'Variant' and 'TCaption'
[Fatal Error] EDORDERS.PAS(76): F2063 Could not compile used 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.
This will result in 3 hints, 1 warning, and 2 errors.
[Error] EDORDERS.PAS(105): E2010 Incompatible types: 'Variant' and 'Double'
[Warning] EDORDERS.PAS(229): W1050 WideChar reduced to byte char in set expressions
[Fatal Error] BrCstOrd.pas(48): F2063 Could not compile used unit 'EDORDERS.PAS'
The error should be known by now, as well as the solution. The warning will be taken care of at the end of the cycle - first let's spend our efforts solving the compiler errors.
- 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.
This will result in 3 hints, 1 warning, and 3 errors.
- 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.
This will result in 3 hints, 1 warning, and 1 error.
- 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,
DBLookup, Buttons;
- Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This will result in 3 hints, 1 warning, and 2 errors.
- 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.
This will result in 3 hints, 1 warning, and 2 errors.
- 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.
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' ,
Brparts in 'BRPARTS.PAS' ,
QryCust in 'QryCust.pas' ,
Edparts in 'EDPARTS.PAS' ,
BrCstOrd in 'BrCstOrd.pas' ,
Edcust in 'EDCUST.PAS' ,
Edorders in 'EDORDERS.PAS' ,
SrchDlg in 'SrchDlg.pas' ,
Splash in 'SPLASH.PAS' ,
Pickdate in 'PICKDATE.PAS' ,
About in 'ABOUT.PAS' ,
Pickrep in 'PICKREP.PAS' ,
PickInvc in 'PickInvc.pas' ,
DataMod in 'DataMod.pas' ;
A nice quick way to place source lines in comments is to press the Ctrl+/ keys. This keystroke will toggle a line of code from uncommented to commented, and move the cursor to the next line. So you can quickly place all three lines in comments.
*Note that you can also select a block of lines of code and then press Ctrl+/ to place the entire block in comments all at once.
- 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(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).

Delphi 2005 Find in Files
*Note that we can group the results by file, and the results will be displayed in a new treeview. As a result, the Main.pas unit is shown.
- 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).

Cannot resolve unit names- plus other uncompilable code
- 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.
The next error is shown in the PrintCustomerReport method.
- 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
with MastData.CustByLastInvQuery do
begin
Open;
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
end;
- Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
This time, the project compiles and links without problems.
DatabasePath
There's one more thing that needs some attention. If you run the application now, there's a chance that it will work but there's also a good chance that you'll get the message that the database could not be located.
This last issue is actually caused by the code in the application itself. Inside the data module, there's a function called DataDirectory, which is defined as follows:
function TMastData.DataDirectory: string;
begin
Result := ExtractFilePath(ParamStr(0));
Result := ExpandFileName(Result + '..\..\..\..\..\Common Files\Borland Shared\DATA\');
end;
As the comments say, it's an assumption that the data is located in ..\..\..\..\..\Common Files\Borland Shared\DATA\data relative to where this application is located. This may work for the Demo directory structure, but is not something I would like to use when deploying the application.
In fact, right at the beginning when we started to migrate this project, we made sure that the database could be connected to at design-time. So the Database.DatabaseName is already pointing to the right place.
The DataDirectory function is used in one place: the MastDataCreate method. And we have to undo what's being done there.
- 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;
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.
- Press Shift+F2 to Save All files in the project, and then press Shift+F9 to rebuild the project.
The project again compiles and runs, showing the Marine Adventures Order Entry application, as follows:

Marine Adventures Order Entry main application
- Click on the New Order button for the Order Form:

Order Form
- Close the Order Form and Click on the Browse button for the Orders by Customer Form:

Orders by Customer Form
- Close the Orders by Customer Form and Click on the Parts button for the Browse Parts Form:

Browse Parts Form
- Close the Browse Parts Form and Click on the Reports button for the Report Selection Form:

Report Selection Form
*Note that neither of the three reports will be available - the buttons are not working - because we placed all use of QuickReports and the reporting forms in comments. Feel free to add your own reports.