Archive for the ‘.NET Tips’ Category.

Migrating Delphi Applications to .NET

I just came by a fairly new set of Delphi tools by CodeGear and RemObjecs, and being an ex Delphi programmer, my mind was flooded with intriguing ideas. How easy would it be to port old Delphi applications into this century, i.e. the .NET world, without the need of a complete rewrite? This would not be the first time it is attempted, but would it be easier now with these brand new tools?

If you have read so far, you probably already know what Delphi is. What you might not know is that CodeGear (now owned by Embarcadero Technologies) released a new .NET version of Delphi just a few months ago. Called Delphi Prism (just Prism here from now on), this MS Visual Studio plug-in is based on Oxygene CLR compiler licensed from RemObjects and fully compliant with the .NET Framework. Both Delphi and Prism compile their own dialect of the Pascal language, of course.

The first attempt towards .NET by Borland/CodeGear was Delphi.NET that first appeared as Delphi 8 in 2003. At first it aroused some enthusiasm, but after all it was no success and was never updated to .NET Framework 2.0. Oxygene/Prism, on the other hand, is not based on Delphi.NET and supports the whole .NET Framework up to version 3.5 and probably beyond.

Porting Delphi Code to .NET

Now, thanks to Prism, you might think that in order to get a .NET application all you would have to do is compile the Pascal sources with Prism, with minor syntax adjustments, perhaps. Well, for your disappointment I have to tell you that there is much more to it than just recompiling the source code. Let’s take a look at a minimal Windows application written in Delphi and Prism!

All this application does is stuff the current date and time into a label that was placed on the main form of the application. The Delphi version looks like this:

Delphi sample

And here’s the Prism version:

Prism sample

Because it’s also written in Pascal, this code bears some structural resemblance to Delphi, but the single line of functional code in our application looks quite different in these two cases: label1.Caption := FormatDateTime(‘c’, Now) vs. label1.Text := DateTime.Now.ToString().

For comparison, let’s have a look at the same application in C#:

C# code sample

The key thing here is the library, namely VCL in Delphi vs. .NET Framework in Prism (or C#). Yes, there is a Label control in both environments, but the most important property bearing the text content is named differently. And to get the current date and time, you would access the Now static property of the DateTime .NET class in Prism whereas in Delphi you would call the Now function that is not part of any class – to say nothing of the formatting of this DateTime value into a string. And this is just the beginning!

Delphi.NET tried to cloak the .NET Framework with VCL.NET, a VCL look-alike that acted as a wrapper around the .NET Framework and implemented the essentials of VCL as calls to .NET. It must have been quite a job to create VCL.NET, and porting it to .NET Framework 2.0 seems to have been even a harder one because it was never really attempted. Moreover, VCL.NET was a dead end because it did not provide a migration path to pure .NET Framework – if you started using VCL.NET, you would be stuck with the VCL object model for the rest of your career!

A more recent undertaking to create a VCL-topping on .NET Framework is ShineOn, an Open Source project initiated by CodeGear. The current version, sorry to say, is just a skeleton that has barely anything implemented. Knowing what happened to VCL.NET, one cannot expect very much from this project. It would be a daunting task to develop a comprehensive VCL replacement that perfectly maps VCL to .NET and does it with no performance penalty.

If these problems with libraries are not enough, look at the Delphi and Prism code samples above! Starting with the word Namespace, there are differences in structure and syntax that originate from the fact that Prism is a .NET language. To alleviate this problem, RemObjecs is developing a tool named Oxidizer that promises to “take care of a lot of the grunt work” that is needed when porting code with manual tools such as search and replace. When it works, Oxidizer can be a great help, but in the end reviewing and finishing the Prism code is something you will always have to do manually in the code editor.

Converting Visual Layouts

You may have noticed that the code samples above were not complete Windows programs – the visual form layouts were missing. We know that VCL forms store they layouts in .dfm files whereas the .NET form designer writes normal program code (Windows Forms) or XAML (WPF). Translating text-based .dfm code to C#, Pascal or XAML is basically something a translator program could do provided it knows the mapping between the UI controls and their properties in VCL and Windows Forms or WPF. Such a tool does not exist yet, but building one is the least of our problems. Even if the tool cannot find a 100 % mapping between the libraries, the amount of manual work is essentially smaller than porting general-purpose program code.

Best of Both Worlds: Running Side by Side

Another option to migrate to .NET would be keep your old native Delphi code as it is and link it with new managed code written in Prism. Calling unmanaged code from Prism or C# is no big deal, but the opposite is also possible. Although linking managed assemblies to Delphi is not as straightforward as linking native Delphi units, it can be done using one of a few routine methods that developers use every day when they move from C, C++ or Visual Basic 6 to C#.

The most common method is to use COM. Assemblies written with Prism or C# can be registered as COM objects that Delphi is able to call, and vice versa. The downside of COM is those woes that made .NET so welcome: the necessity to register all COM objects and the notorious DLL Hell. Were your application anything but trivial, very soon you would have to register and maintain several COM interfaces between Delphi and .NET.

Another method is to use mixed-mode DLL’s that have interfaces to both .NET and native WIN32 code. Unfortunately, they must be written in C++ so you would have to add a third programming language in the mixture.

But luckily there’s still another method, from RemObjects, again! They are selling a tool named Hydra that is based on the concept of plugins. Both plugins and plugin hosts can be written using Delphi or a .NET language (Prism, C# etc.), and thus Delphi applications can host .NET plugins, and .NET applications can host Delphi plugins. Plugins can be visual (kind of user controls) and non-visual (e.g. business components).

Hydra provides a set of wizards and helper components that open windows to the other world through interfaces. Calling the other side through an interface requires some typecasting or late binding, but it seems to work. The best thing is that Hydra does not use COM.

Which Way to Go?

As we have seen, porting Delphi code through Prism to the .NET world is not as easy as it would seem at first glance. If your code interacts with the user interface or relies heavily on VCL components such as datasets, there will be lots of manual work ahead. Only if your code mainly deals with your own classes and barely touches the run-time library, the porting solution would be feasible, but because we are porting a RAD solution, such a situation should not be very frequent. After all, the idea behind RAD has been to rely on smart components and controls, not to write everything from scratch.

What I would recommend is to start in a step-by-step fashion and implement new features and modules as .NET plugins. Depending on the structure of your application, a whole application layer, say the data access layer, could also be implemented as a .NET plugin. A VCL ClientDataSet fed by an ADO.NET plugin sounds quite realistic.

Over time, more and more modules would be migrated, and one day you could translate your form layouts from DFM to XAML, run a raw code translation to Prism with Oxidizer and hand-tune the rest. Personally, I would translate the code all the way to C#, but it’s your choice which .NET language you like to use.

If you are planning to stick with Delphi and completely ignore the evolving .NET world around you, don’t do that for long now! There are .NET technologies such as WCF that are likely to become a must on any line of business, and failing to support them makes your application hopelessly outdated. Delphi was a great tool that opened new perspectives for application development and influenced .NET and C# more than is generally known. The best way to pay homage to Delphi is to give Delphi applications an honorable old age and a chance to be reborn as .NET applications.

Scalable Windows Forms

Consider an application that should be able to adapt its font and form size to various needs: for users with weak eyesight, for viewing from different distances etc. You might think you need WPF to do that, but in fact also plain old Windows Forms has got mechanisms that automatically scale fonts and form layouts to different screen resolutions and font sizes. With a minimal amount of code you will be able to utilize this mechanism in your own application to make a fully scalable UI.

Scaling Support in Windows Forms

Today a Windows application might have to run in environments with several screen resolutions and system font sizes. As a programmer, what should you do to ensure your application would keep its layout and be consistent with the rest of the environment whatever the screen resolution might be? Well, you don’t have to do anything! Just leave your form’s AutoScaleMode property to Font for text-based forms (with labels, text boxes and buttons) or set it to Dpi for graphics-based forms, and Windows and the .NET Framework will scale your UI to fit the current environment. You can test your application by running it in different DPI settings. To change the DPI setting of your system, open Control Panel -> Display -> Settings -> Advanced -> General in XP or Control Panel -> Personalization -> Adjust font size (DPI) in Vista.

Scaling Your Own Application

Changing the DPI setting requires restarting the system so it isn’t very handy if your user just temporarily wants to see the application in a magnified or reduced view. This is why you might consider having individual UI scaling in your application. Thanks to the automatic scaling support in Windows Forms it will be quite easy and straightforward.

When you change the Font property of a Form (programmatically or in Designer) to a larger or smaller font, form dimensions and control layout will scale automatically provided that the AutoScaleMode property is set to Font. If you try this, you will notice that controls on this form might also have their font size changed. The problem is that the general font change only applies to those controls whose Font property has not been set explicitly. These controls assume the font of their parents (Form, GroupBox, Panel etc.), and automatic font change works only as far as this chain from form to controls is not broken.

To spread the relative font change to all controls you just need to add a few lines of code that goes through all controls on the form and changes the font of those who don’t share a font with their parent. This can be done by overriding the OnFontChanged method or implementing a FontChanged event handler. And that’s it!

The Sample Application

A tiny Visual Studio 2005 project with a launcher/control form and two scalable forms can be found in http://www.sysgen.fi/source/scalableforms. For your convenience it is available both as a ZIP archive and as separate files. The first scalable form isn’t fully scalable since the label “This form has got nothing special in it” does not scale because it does not share the font with the form. The second one scales nicely thanks to the OnFontChanged override.

When running the application, you may open any number of the two forms and see the effect of dragging the track bar slider. Please enjoy!

Sharing Status between Forms

A typical Windows Forms application might have several forms open at one time. Often these forms share an entity, e.g. they might all be documents related to one customer. Attaching the forms to a customer at creation time is trivial, but making all the forms reflect changes in customer state in real time isn’t. In this example I’ll show a simple mechanism how to bind any number of forms to a set of shared live data.

The Scenario

Let’s assume we have an application where we first select a customer an then create or open any number of invoices (or other documents) related to this customer. A dedicated customer form is used for updating customer details, but in addition to that, any document form might also be used to keep customer data (e.g. the mailing address) up to date. Once a form updates the customer details, all the other forms should reflect the change immediately. The customer might also have calculated characteristics that are not saved as customer data but calculated from documents.

To accomplish this task, we would typically create a network of methods, delegates and events that spreads the signal of data changes between forms. Luckily we don’t have to do that because we already have a mechanism that is easy to use and encapsulates all the methods, delegates and events needed for signaling data changes, namely data binding

The Solution

We create a component class named CustomerSource that inherits from BindingSource. Thanks to its parent class, this component can be dropped on a form, and data controls can be bound to it visually. CustomerSource is internally bound to a typed DataSet, or, to be exact, to a DataTable within that DataSet.

What makes this BindingSource special is that the DataSet is contained in a static member:

private static CustomerDataSet DS = new CustomerDataSet();

This means that a single copy of CustomerDataSet is created when the code for CustomerSource is first loaded. The copy is kept in memory as long as the application runs. Because this single copy is shared by all instances of the class, all the forms that contain a CustomerSource have access to this shared data.

CustomerSource has a double role both as a data model and a controller. It has methods for retrieving, saving and refreshing customer data. These methods are documented in source code.

The Sample Code

You can download the Visual Studio 2005 solution at http://www.sysgen.fi/source/interformcomm. For your convenience it is available both as a ZIP archive and as separate files.

The solution is structured as three Visual Studio projects mainly to demonstrate that static data is not bound to one assembly.

Customer data access uses Microsoft’s Northwind sample SQL Server database. Please open CustomerDataAccess.cs and make sure that sqlConnection1.ConnectionString points to your copy of Northwind if you have got one. If you haven’t got SQL Server or this database, you can run the solution by commenting out an in a few lines in CustomerDataAccess.cs – see source code for instructions! The data access implementation is intentionally simplified: you won’t find any data validation or error handling there.

Enjoy!