Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Delphi

.NET Runtime Library for Delphi

4.62/5 (6 votes)
11 Oct 2015CPOL4 min read 20.5K  
.NET Runtime Library for Delphi

Introduction

Delphi developers can access .NET libraries through COM technology which requires Library registrations and a whole lot of stuff before the inter-process communication between the Delphi Type Library objects and the .NET Library object types can be established. The era of creating and registering a Type Library for .NET Libraries in Delphi is finally over. CrystalNet Technologies have introduced .NET Runtime Library for Delphi which provides a set of low level routines used by Delphi compiler using COM to invoke the behaviours of the CrystalNet Runtime Environment. The CrystalNet Runtime environment implements the execution model, built-in functions and other fundamental behaviours of a .NET programming language.

Main Features

There are 2 main parts of the .NET Runtime Library for Delphi, these are:

1. CrystalNet Runtime Environment

This is the system which manages .NET Framework Engine and enables inter-process communication between Delphi Applications and .NET libraries. The runtime environment starts the .NET framework engine making it possible for an application written in Delphi to access all the classes in the Microsoft Common Object Runtime Library (mscorlib) or access all the classes in an external library without prior registrations of the Library. The
programming component of the runtime environment is the Runtime Library.

2. CrystalNet Common Object Runtime Library

The CrystalNet Common Object Runtime Library (CNCorLib) is written in both C# and Delphi. The C# CNCorLib (also called CrystalNet Runtime Library) is a .NET assembly which is tightly coupled with the CrystalNet Runtime Environment. The Delphi part of the runtime library (CRLHost, also called Delphi Runtime Host Library) is a dispatch interface implementation of the CrystalNet Runtime Library which serves as a bridge between Delphi
and .NET processes.

Load .NET Libraries in Delphi

There are several ways to load .NET libraries into the runtime host application domain. A library can be loaded using the load methods defined in the runtime host (CorHostManager) or use the runtime host’s AppDomain and AssemblyEx properties or create an instance of _AppDomain and _AssemblyEx, and use the load, LoadFrom, UnsafeLoadFrom, ReflectionOnlyLoad, etc. methods to load the .NET library.

Create Instance of .NET Library Type

Delphi Runtime Library provides numerous ways to create an instance of a type whose assembly has been loaded into the runtime host application domain. The runtime host manager (CorHostManager) has a property that defines the runtime current application domain. The property is called AppDomain. Any assembly loaded is attached to this AppDomain so that retrieving the type using the type name or creating an instance of a type which belongs to the loaded assembly can be possible. An error is triggered if the type does not exist in any of loaded assemblies in the domain. In .NET, to create an instance of a type you can use Activator Class, AppDomain Class, etc. Similarly, you can use _Activator interface type, _AppDomain interface type and CorHostManager AppDomain property to create an instance of a .NET object in Delphi.

Note: The type of .NET objects created in Delphi using the runtime library is Olevariant (It can be IDispatch).

Event Handling and Callbacks

Events in the .NET Framework are based on the delegate model. An event is a message sent by an object to signal the occurrence of an action. The object that raises the event is called the event sender. The event sender doesn't know which object or method will receive (handle) the events it raises. The event is typically a member of the event sender. The .NET Framework follows a naming pattern of ending all event data classes with EventArgs.

Example of standard .NET Framework event delegate:

C++
public delegate void StateChangeHandler (Object sender, StateChangeEventArgs e);

A delegate is a type that holds a reference to a method. A delegate is declared with a signature that shows the return type and parameters for the methods it references, and can hold references only to methods that match its signature. A delegate is thus equivalent to a function pointer or a callback in Delphi. The Runtime Library allows only 2 Callback method or function pointer parameters. This is a standardized way of defining event delegates in .NET. The first parameter is the sender which raises the event and is the same as the instance object created in Delphi which invoked the event. The second parameter is the EventArgs which is a data that is associated with an event and can be provided through an event data class. To access the members of an event data class in Delphi, you can use CNObject Interface, reflection or add DispId to the event class members in the .NET library and create a DispInterface type of the event data class in Delphi. A stdcall calling conversion is added to the callback method to ensure parameters are passed and push on to the stack from right to left in the parameter list of the function pointer or callback method.
The following are examples of Delphi Callback method for the above .NET delegate:

Assuming StateChangeEventArgs class in C# has a get and set property called State.

Example 1: Using CNObject Interface to access the event data class members of StateChangeEventArgs:

C++
procedure StateChangeHandler(sender: Olevariant; e : IDispatch); stdcall;
var
  oStateValue: Integer;
  StateChangeEventArgs: _CNObject;
begin
  StateChangeEventArgs := CorHostManager.CastObjectAs(e);
  oStateValue:= StateChangeEventArgs.GetPropertyValue('State');
end;

Example 2: Using reflection to access the event data class members of StateChangeEventArgs.

C++
procedure StateChangeHandler(sender: Olevariant; e : IDispatch); stdcall;
var
  oStateValue: Integer;
  EventArgsType: _Type;
begin
  EventArgsType:= CorHostManager.GetType(e);
  oStateValue:= EventArgsType.GetProperty('State').GetValue(e);
end;

Example 3: Create DispInterface Type to access the event data class members of StateChangeEventArgs.

C++
//C# Library StateChangeEventArgs Modification
public class StateChangeEventArgs
{
  [DispId(0)]
  public int State {get; set ;}
}

//Delphi Corresponding StateChangeEventArgs Dispatch Interface
_StateChangeEventArgs = dispInterface
['{55BF5363-248D-4D10-A8D4-A711BF96DFA6}']
  property State : Integer dispId 0;
end;

procedure StateChangeHandler(sender: Olevariant; e: _StateChangeEventArgs); stdcall;
var
  oStateValue: Integer;
begin
  oStateValue:= e. State;
end;

//OR

procedure StateChangeHandler(sender: Olevariant; e: _IDispatch); stdcall;
var
  EventArgs: _StateChangeEventArgs;
  oStateValue: Integer;
begin
  EventArgs := _StateChangeEventArgs(e);
  oStateValue:= EventArgs. State;
end;

For more information and to download the latest runtime library, go to http://sourceforge.net/projects/dotnetruntimelibraryfordelphi/.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)