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
:
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
:
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
.
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
.
public class StateChangeEventArgs
{
[DispId(0)]
public int State {get; set ;}
}
_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;
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/.