The VCL

The VCL

The .NET Framework classes in the System.Windows.Forms namespace are not a replacement for the GUI portion of the Win32 API. The same happens with most other portions of the .NET Framework: its role is to make the underlying API easier to use by providing an easier object-oriented interface compatible with the core services of the .NET environment. The GUI subset of Win32 is still there, occupying the same place it always has. System.Windows.Forms organizes this GUI subset of the Win32 API, presents it in an object-oriented way, and layers an event model on top of it; but classes in System.Windows.Forms call the unmanaged code in Win32. When you use System.Windows.Forms, you are still calling the Win32 APIs, but now you have a large layer of software called the CLR sitting between your code and Win32.

This entire preamble is important to acknowledge why the VCL takes this same approach. TObject is rooted (if you will) from System.Object through the use of a class helper. TPersistent and TComponent still descend from there. Thus the VCL class TForm, for example, is not a descendant of the class System.Windows.Forms.Form. Instead, the entire VCL hierarchy remains much as it is today. TForm will ultimately descend from TWinControl, which itself is a descendant of TControl and then TComponent.

If you consider the entire System.Windows.Forms namespace as a single entity, the VCL then becomes a kind of sibling to it, rather than a child of it. Both frameworks ultimately rely on the native, unmanaged Win32 API for the underlying implementation of the user interface controls.

Looking into the VCL.NET Source

The update of the Delphi .NET Preview compiler made available by Borland in November 2002, although still preliminary, provides details about the architecture the company is planning. If you open the Borland.Vcl.Controls unit, you'll be surprised by its similarity to the Win32 version. The source code is almost identical; the differences exist behind the scenes at the TObject and TComponent level. I've already covered the former, so let's focus on the core component class, which is defined in three steps:

type
  TComponent = System.ComponentModel.Component;
  TComponentHelper = class helper (TPersistentHelper) for TComponent
  TComponentSite = class(TObject, ISite, IServiceProvider)

The TComponent class corresponds to the .NET Framework class, with a helper providing extra methods and properties and a further class offering the extra data required by the helper class. The situation is complex, and I don't want to get into the details because the TComponent class is marked as experimental and may change in further updates.

Getting back to the VCL, a large set of components is already available, so you can begin porting code. The only trouble you'll face with the November 2002 update is that streaming is not supported; so, you must add the component-creation code in the form constructor (an action that will not be required by the final version of Delphi for .NET).

As an interesting example to help you figure out the architecture of the VCL classes, I've ported to .NET the ClassInfo example from Chapter 3, "The Run-Time Library." The NetClassInfo example uses this modified code in the project source (again, something you won't have to do in the future):

Application.Initialize;
Form1 := TForm1.Create (Application);
Application.MainForm := Form1;

The code for the form, as I've mentioned, has an extra method called by the constructor and used to initialize the controls. This method is quite long, so I'll provide only a few excerpts here:

procedure TForm1.InitializeControls;
begin
  // creating all controls...
  Label3:= TLabel.Create(Self);
  Panel1:= TPanel.Create(Self);
  Label1:= TLabel.Create(Self);
  Label2:= TLabel.Create(Self);
  ...
   
  // setting form properties and events
  Left:= 217;
  Top:= 109;
  Caption:= 'Class Info';
  OnCreate:= FormCreate;
   
  // initializing controls (only one is listed here)
  with Label3 do
  begin
    Parent:= Self;
    Left:= 8;
    Top:= 8;
    Width:= 56;
    Height:= 13;
    Caption:= 'Class Name';
  end;

The rest of the application's code remains almost identical, which is surprising considering that this is a low-level example. I had to remove the call to InstanceSize, because the compiler cannot resolve the size of an object given the architecture of .NET, and I had to test for the base class against Object instead of TObject. Here is the code snippet that produces the output shown in Figure 25.1:

procedure TForm1.ListClassesClick(Sender: TObject);
var
  MyClass: TClass;
begin
  MyClass := ClassArray [ListClasses.ItemIndex];
  EditInfo.Text := Format ('Name: %s - Size: %d bytes',
    [MyClass.ClassName, 0 {MyClass.InstanceSize}]);
  with ListParent.Items do
  begin
    Clear;
    while MyClass.ClassName <> 'Object' do
    begin
      MyClass := MyClass.ClassParent;
      Add (MyClass.ClassName);
    end;
  end;
end;
Click To expand Figure 25.1:  The NetClassInfo example shows the base classes of a given component.

Further VCL Examples

To provide starting points for your own experiments with the VCL under .NET, I've built two more examples. NetEuroConv is a port of the EuroConv example from Chapter 3 based on the RTL's conversion engine. NetLibSpeed is a port of the LibSpeed example used in Chapter 5 ("Visual Controls") to compare the VCL and VisualCLX libraries' speed in creating visual components. The number you'll see makes little sense in such a preliminary version of a library, although the fact that VCL.NET takes four to five times as long for the same purpose may worry you.

As I mentioned, these examples are meant to be only starting points for your experiments. They may not work with further updates of the Delphi for .NET Preview.

Note 

Stay tuned to my website for updates of this section of the book and the related examples.



Part I: Foundations