.Net Runtime Library for Delphi

The .Net Runtime Library for Delphi is the best library to work with .Net framework from Delphi. It is designed to provide a way to interact with applications written in anyone of the .Net langauges such as C#, Visual Basic.Net, Delphi.Net, JScript.Net and others.


Many years ago, in the middle of 90's, Microsoft introduced a new revolutionary programming technology called COM (Component Object Model). It is used to enable inter-process communication and dynamic object creation in a large range of programming languages.COM is a platform-independent, distributed, object-oriented system for creating binary software components that can interact. Most new windows OS features were implemented using COM. Most programming languages support COM but most of them are not COM-based.

Now Microsoft has introduced a new revolutionary technology which is more powerful than COM called .Net. New programming languages such as C#, VB.Net, Visual C++ etc were created using the .Net technology. More and more new .Net components become available on the market.

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 because of the new technology called .Net Runtime Library for Delphi introduced by CrystalNet Technologies LTD which provides a set of low-level routines used by Delphi compiler to invoke the behaviours of the Common Language Runtime.

The .Net Runtime Library for Delphi is the best library to work with the .Net framework from Delphi. It is designed to provide a way to interact with applications written in anyone of the .Net languages: C#, Visual Basic.Net, Delphi.Net, JScript.Net and others. Programmers can produce software by combining pascal source codes with .Net framework and other .Net libraries.


The .Net Runtime Library for Delphi can be used to:
  • Hosts the .Net Common Language Runtime (CLR) in Delphi.
  • Loads assemblies from .Net dll or executable file without registering the Library as COM in Delphi.
  • Loads .Net assemblies from Global Assembly Cache (GAC) without prior registration of the assembly types as COM.
  • Accesses .Net assembly types and members of the types which includes fields, properties, methods events etc.
  • Creates an instance of a .Net object from the types of the loaded assemblies.
  • Calls static and non-static members of the .Net types from the loaded assemblies. The members include fields, properties, methods and events.
  • Handles and raises .Net exceptions and also get information about the type of the exception.
  • Accesses, handles and invokes .net events and delegates from Delphi.
  • Contains all the assemblies and types in the .Net Framework Class Libraries.
  • Hosts .Net controls in Delphi Forms.
  • Contains a utility which imports .net dll, executable or Web Service Definition Language (WSDL) and generates Delphi classes from the loaded assemblies.
  • and many more.

There are 2 main libraries that constitutes the .Net Runtime Library for Delphi, these are:

1. Host Class Library

This is also called Delphi Host Class Library or DHCL. This Library contains Delphi classes and interfaces for starting and hosting the .Net Common Language Runtime (CLR) which allows Delphi applications to load and access .net assemblies, create object instance of the types from the loaded assembly, invoke the members of the types etc. The CLR manages memory, thread execution, code execution and other system services.

Learn more »

2. Framework Class Library

The Delphi Framework Class Library (DFCL) is a Delphi interface representation of the .NET Framework class library which is a collection of reusable types that tightly integrate with the Delphi Host Class Library.

Learn more »

.Net Assembly/WSDL Importer

A tool which is part of the .Net Runtime Library for Delphi is used to import .net assemblies, WSDL or Web Service XML schema and generates Delphi classes from the types of the imported assemblies.

Learn more »



Note: The Runtime Library will not turn your Delphi into .Net language.


.Net Runtime Library for Delphi comes in three editions: Standard, Enterprise and Professional.

Standard Edition is a cost-effective solution for developers to access .net assemblies from Delphi.

Enterprise Edition extends Standard Edition with full access to the .Net Framework Class Library.

Professional Edition extends Enterprise Edition with .net assembly and wsdl import tools.

All the editions contains the source codes for the library classes and interfaces.

The matrix below compares features of Runtime Library editions.

Features Standard Enterprise Professional
Host Class Library Yes Yes Yes
Framework Class Library No Yes Yes
.Net Assemblies/WSDL Importer Utility No Yes Yes
Single License Price $99.95 $119.95 $129.95

IDE Compatibility

The Runtime Library integrates with the following Embarcadero Delphi products:
  • Delphi 2009
  • Delphi 2010
  • Delphi XE
  • Delphi XE2
  • Delphi XE3
  • Delphi XE4
  • Delphi XE5
  • Delphi XE6
  • Delphi XE7
  • Delphi XE8
  • Delphi 10.0 Seattle
  • Delphi 10.1 Berlin
  • Delphi 10.2 Tokyo

.NET Framework 4.5 Service Pack 1 or higher is required for the Runtime Library.


6.0.0.1 14-Aug-2017
  • Fixed bug with creating an instance of the TClrObjectArray or TClrArray Class
  • Fixed bugs in .Net Assembly/WSDL Import Tools to generate Delphi codes from .Net assemblies/WSDL without compiler errors.
  • Changed return type of the methods for loading .net assemblies in TClrAssembly and TClrAppDomain Classes from TClrAssembly to _Assembly interface in order to prevent possible memory leaks if the user forgets to free the loaded .net assemblies.
  • Fixed "Constructor on type 'CNClrLibrary.Security.Cryptography.Cryptostream' not found" error

6.0.0.0 01-Jun-2017
  • Implemented mscorlib types as part of the runtime library
  • Added new classes and improve the existing classes in the host class library
  • Support .Net Framework 4.5.2 or Higher
  • Support Delphi 2009 or Higher
  • Added .Net Assembly/WSDL Import Tools
  • Usability improvements
  • Stability and performance improvements

5.0.0.0 10-Oct-2015
  • Major changes to the Runtime Library
  • Support 64bit Delphi application

4.0.3.1 05-May-2015
  • Support .Net Framework 4.5 or Higher

4.0.3.0 15-Feb-2015
  • Fixed bugs in CryptoStream type interface to avoid the error ""EOleException: Constructor on type 'CNCorLib.Sys.Security.Cryptography.CryptoStream' not found"

4.0.2.0 01-Dec-2014
  • Fixed bugs in Runtime Host class to prevent "System.NullReferenceException"

4.0.1.0 05-Sep-2014
  • Fixed bugs in Mscorlib type interfaces

4.0.0.0 29-Oct-2014
  • Added Delphi Framework Class Library
  • Support .Net Framework 4.0 or Higher
  • Support Delphi 7 and Higher

2.0.0.0 23-Jan-2014
  • Fixed bugs with I/O operations
  • Usability improvements
  • Stability and performance improvements

1.0.0.0 01-Aug-2013
  • First release of .Net Runtime Library
  • Delphi 7 is supported
  • Support .Net Framework 3.0

The following examples demonstrate how to use the .Net Runtime Library for Delphi to produce a software by combining pascal source codes with .Net framework and other .Net libraries.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Basic Examples\Console App\ConsoleApp.dpr program ConsoleApp;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils,
{$ELSE}
  SysUtils,
{$IFEND}
  CNClrLib.Core;

var
  Console : _Console;
begin
  Console := CoConsole.CreateInstance;
  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('The program displays the string Hello World!');
  Console.WriteLine;
  Console.WriteLine_14('Hello World!');
  Console.WriteLine_14('Press any key to exit.');
  Console.ReadKey;
end.
C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Application Domains and Assemblies\Load Assemblies\Using AppDomain\LoadAssemblyUsingAppDomain.dpr program LoadAssemblyUsingAppDomain;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils,
{$ELSE}
  SysUtils,
{$IFEND }
  CNClrLib.Host, CNClrLib.Core;

var
  Console : _Console;

  procedure DisplayAssemblyInfo(AAssembly : _Assembly);
  begin
    if AAssembly = nil then
      Console.WriteLine_14('Assembly cannot be loaded')
    else
    begin
      Console.WriteLine_14('Assembly has been loaded');
      Console.WriteLine_15('Is Fully Trusted:      {0}', AAssembly.IsFullyTrusted);
      Console.WriteLine_15('Global Assembly Cache: {0}', AAssembly.GlobalAssemblyCache);
      Console.WriteLine_15('Location:              {0}', AAssembly.Location);
      Console.WriteLine_15('Image Runtime Version: {0}', AAssembly.ImageRuntimeVersion);
      Console.WriteLine_15('Number of Types:       {0}', AAssembly.GetTypes.Length);
      Console.WriteLine;
      Console.WriteLine;
    end;
  end;
  
  procedure LoadAssemblyByAssemblyString;
  var
    m_assembly: _Assembly;
  begin
    Console.WriteLine_14('Loading System.Data.dll using Assembly String');

    m_assembly := TClrAppDomain.GetCurrentDomain.Load('System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089');
    DisplayAssemblyInfo(m_assembly);
  end;

  procedure LoadAssemblyByAssemblyName;
  var
    m_assemblyName : _AssemblyName;
    m_assembly : _Assembly;
  begin
    Console.WriteLine_14('Loading System.Data.dll using AssemblyName Properties and methods');

    m_assemblyName := CoAssemblyName.CreateInstance;
    m_assemblyName.Name := 'System.Data';
    m_assemblyName.Version := CoVersion.CreateInstance('2.0.0.0');
    m_assemblyName.CultureInfo := CoCultureInfo.CreateInstance('');
    m_assemblyName.SetPublicKeyToken(TClrArrayHelper.ToByteArray('b77a5c561934e089'));
    m_assembly := TClrAppDomain.GetCurrentDomain.Load(m_assemblyName);
    DisplayAssemblyInfo(m_assembly);
  end;

  procedure LoadAssemblyByAssemblyNameString;
  var
    m_assemblyName : _AssemblyName;
    m_assembly : _Assembly;
  begin
    Console.WriteLine_14('Loading System.Data.dll using AssemblyName with AssemblyString');

    m_assemblyName := CoAssemblyName.CreateInstance('System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089');

    m_assembly := TClrAppDomain.GetCurrentDomain.Load(m_assemblyName);
    DisplayAssemblyInfo(m_assembly);
  end;

begin
  Console := CoConsole.CreateInstance;
  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('The program demonstrate how to use AppDomain to Load .Net Assemblies');
  Console.WriteLine;

  try
    LoadAssemblyByAssemblyString;
    LoadAssemblyByAssemblyName;
    LoadAssemblyByAssemblyNameString;
  except
    on E:Exception do
      Console.WriteLine_15('Exception : {0}', E.Message);
  end;
  Console.ReadKey;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Application Domains and Assemblies\Create Instance\Using Activator\CreateInstanceUsingActivator.dpr program CreateInstanceUsingActivator;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils, System.Variants,
{$ELSE}
  SysUtils, Variants,
{$IFEND}
  CNClrLib.Host, CNClrLib.Core;

var
  Console : _Console;
  Activator : _Activator;

  procedure DisplayObjectTypeInfo(AObject : OleVariant);
  var
    m_type : _Type;
  begin
    if VarIsEmpty(AObject) or VarIsClear(AObject) then
      Console.WriteLine_14('object has not been instantiated')
    else
    begin
      m_type := TClrAssembly.GetObjectType(AObject);
      Console.WriteLine_14('object has been instantiated');
      Console.WriteLine_15('Assembly FullName:     {0}', m_type.Assembly.FullName);
      Console.WriteLine_15('FullName:              {0}', m_type.FullName);
      Console.WriteLine_15('GUID:                  {0}', m_type.GUID.ToString);
      Console.WriteLine_15('ToString:              {0}', m_type.ToString);
      Console.WriteLine;
      Console.WriteLine;
    end;
  end;

  procedure CreateInstanceFromAssemblyString;
  var
    m_sqlConnHnd : _ObjectHandle;
  begin
    m_sqlConnHnd := Activator.CreateInstance_5('System.Data, Version=2.0.0.0, Culture=neutral, ' +
                  'PublicKeyToken=b77a5c561934e089', 'System.Data.SqlClient.SqlConnection');
    DisplayObjectTypeInfo(m_sqlConnHnd.Unwrap);
  end;

  procedure CreateInstanceFromTypeName;
  var
    m_sqlConnobj : OleVariant;
    m_sqlConType : _Type;
  begin
    TClrAssembly.Load('System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089');
    m_sqlConType := TClrAssembly.GetType('System.Data.SqlClient.SqlConnection', True);
    m_sqlConnobj := Activator.CreateInstance_4(m_sqlConType);
    DisplayObjectTypeInfo(m_sqlConnobj);
  end;

  procedure CreateInstanceFromTypeWithParam;
  var
    m_qlConnHnd : OleVariant;
    m_objArray : _ObjectArray;
    m_sqlConType : _Type;
  begin
    //Create Instance with a parameter
    m_objArray := CoObjectArray.CreateInstance(1);
    m_objArray[0] := 'Data Source=myServerAddress;Initial Catalog=myDataBase;User ID=myDomain\myUsername;Password=myPassword;';

    //Assembly has been loaded in CreateInstance2, no need to reload assembly
    m_sqlConType := TClrAssembly.GetType('System.Data.SqlClient.SqlConnection', True);
    m_qlConnHnd := Activator.CreateInstance_2(m_sqlConType,  m_objArray);
    DisplayObjectTypeInfo(m_qlConnHnd);
  end;

  procedure CreateInstanceFromFile;
  var
    m_sqlConnobj : _ObjectHandle;
  begin
    m_sqlConnobj := Activator.CreateInstanceFrom('C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll',
        'System.Data.SqlClient.SqlConnection');
    DisplayObjectTypeInfo(m_sqlConnobj.Unwrap);
  end;

begin
  Console := CoConsole.CreateInstance;
  Activator := CoActivator.CreateInstance;
  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('The program demonstrate how to use Activator interface to Create Object Instance');
  Console.WriteLine;
  try
    CreateInstanceFromAssemblyString;
    CreateInstanceFromTypeName;
    CreateInstanceFromTypeWithParam;
    CreateInstanceFromFile;
  except
    on E:Exception do
      Console.WriteLine_15('Exception : {0}', E.Message);
  end;
  Console.ReadKey;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Application Domains and Assemblies\Create Instance\Using Dispatch Activator\CreateInstanceUsingDispActivator.dpr program CreateInstanceUsingDispActivator;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils, System.Variants,
{$ELSE}
  SysUtils, Variants,
{$IFEND }
  CNClrLib.Host, CNClrLib.Core;

var
  Console : _Console;
  Activator : TClrDispatchActivator;

  procedure DisplayObjectTypeInfo(AObject : OleVariant);
  var
    m_type : _Type;
  begin
    if VarIsEmpty(AObject) or VarIsClear(AObject) then
      Console.WriteLine_14('object has not been instantiated')
    else begin
      m_type := TClrAssembly.GetObjectType(AObject);
      Console.WriteLine_14('object has been instantiated');
      Console.WriteLine_15('Assembly FullName:     {0}', m_type.Assembly.FullName);
      Console.WriteLine_15('FullName:              {0}', m_type.FullName);
      Console.WriteLine_15('GUID:                  {0}', m_type.GUID.ToString);
      Console.WriteLine_15('ToString:              {0}', m_type.ToString);
      Console.WriteLine;
      Console.WriteLine;
    end;
  end;

  procedure CreateInstanceFromTypeName;
  var
    m_sqlConnobj : OleVariant;
  begin
    TClrAssembly.Load('System.Data, Version=2.0.0.0, Culture=neutral, '+
      'PublicKeyToken=b77a5c561934e089');
    m_sqlConnobj := Activator.CreateInstance('System.Data.SqlClient.SqlConnection');
    DisplayObjectTypeInfo(m_sqlConnobj);
  end;

  procedure CreateInstanceFromTypeWithParam;
  var
    m_sqlConnHnd : OleVariant;
    m_objectArray : _ObjectArray;
  begin
    //Create Instance with a parameter
    m_objectArray := CoObjectArray.CreateInstance(1);
    m_objectArray[0] := 'Data Source=myServerAddress;Initial Catalog=myDataBase;User ID=myDomain\myUsername;Password=myPassword;';
    m_sqlConnHnd := Activator.CreateInstance('System.Data.SqlClient.SqlConnection', m_objectArray);
    DisplayObjectTypeInfo(m_sqlConnHnd);
  end;

begin
  Console := CoConsole.CreateInstance;
  Activator := TClrDispatchActivator.Create;
  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('The program demonstrate how to use Dispatch Activator interface to Create Object Instance');
  Console.WriteLine;
  try
    CreateInstanceFromTypeName;
    CreateInstanceFromTypeWithParam;
  except
    on E:Exception do
      Console.WriteLine_15('Exception : {0}', E.Message);
  end;
  Console.ReadKey;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Application Domains and Assemblies\COM DispInterface\COMDispInterface.dpr program COMDispInterface;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils,
{$ELSE}
  SysUtils,
{$IFEND}
  CNClrLib.Host, CNClrLib.Core;

(*  Mathematics.Dll Source Code
  namespace Mathematics
  {
      public class Mathematics
      {
          [DispId(0)]
          public int Add(int a, int b)
          {
              return a + b;
          }

          [DispId(1)]
          public int Subtract(int a, int b)
          {
              return a - b;
          }

          [DispId(2)]
          public bool Equal(int a, int b)
          {
              return a == b;
          }
      }
  }
*)

type
  //Corresponding Delphi DispInterface type of Mathematics type in the Mathematics.dll
  _Mathematics = dispinterface
  ['{D77959BD-C7AC-4D65-9980-A88510F776B8}']
    function Add(a, b : Integer) : Integer; dispid 0;
    function Subtract(a, b : Integer) : Integer; dispid 1;
    function Equal(a, b : Integer) : WordBool; dispid 2;
  end;

var
  Console : _Console;
  Mathematics : _Mathematics;


  procedure LoadMathematicAssembly;
  begin
    // If error occurs while executing LoadFrom then
    // Right-Click on the file and select properties, click on the
    // unblock button to allow access.
    TClrAssembly.LoadFrom('Mathematics.dll');
  end;

  procedure CreateMathematicTypeInstance;
  begin
    Mathematics := _Mathematics(TClrDispatchActivator.CreateInstance('Mathematics.Mathematics'));
  end;

  procedure AccessMathematicsObjectMethods;
  begin
    Console.WriteLine_15('Add(30, 50):      {0}', Mathematics.Add(30, 50));
    Console.WriteLine_15('Subtract(30, 50): {0}', Mathematics.Subtract(30, 50));
    Console.WriteLine_15('Equal(30, 50):    {0}', Mathematics.Equal(30, 50));
    Console.WriteLine_15('Equal(50, 50):    {0}', Mathematics.Equal(50, 50));
  end;

begin
  Console := CoConsole.CreateInstance;
  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('This program demonstrate how to use COM DispInterface to communicate with .Net library type members');
  Console.WriteLine;
  try
    LoadMathematicAssembly;
    CreateMathematicTypeInstance;
    AccessMathematicsObjectMethods;
  except
    on E: Exception do
      Console.WriteLine_15('Exception: {0}', e.Message);
  end;
  Console.ReadKey;
end.


C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Basic Examples\ClrObject Example\UsingClrObject.dpr program UsingClrObject;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils, System.Variants,
{$ELSE}
  SysUtils, Variants,
{$IFEND}
  CNClrLib.Host, CNClrLib.Enums, CNClrLib.Core;

var
  Console : _Console;
  SQLConnection : IDispatch;
  ConnectionString : WideString;

  procedure CreateClrObjectUsingWrap;
  var
    m_SQLConnection : _ClrObject;
  begin
    Console.WriteLine_14('Wrap the connection object to ClrObject Interface');
    m_SQLConnection := CoClrObject.Wrap(SQLConnection);
    m_SQLConnection.SetPropertyValue('ConnectionString', ConnectionString);

    m_SQLConnection.InvokeMethod('Open');
    Console.WriteLine_14('Connection Opened');
      
    m_SQLConnection.InvokeMethod('Close');
    Console.WriteLine_14('Connection Closed');
    Console.WriteLine;
  end;  

  procedure CreateClrObjectUsingTClrObjectClass;
  var
    m_SQLConnection : TClrObject;
  begin
    Console.WriteLine_14('Using CreateInstance to create CrystalNet Object');
    m_SQLConnection := TClrObject.Create(SQLConnection);
    try
//      m_SQLConnection.OwnsObject := False;
      m_SQLConnection.SetPropertyValue('ConnectionString', ConnectionString);

      m_SQLConnection.InvokeMethod('Open');
      Console.WriteLine_14('Connection Opened');
      
      m_SQLConnection.InvokeMethod('Close');
      Console.WriteLine_14('Connection Closed');
      Console.WriteLine;
    finally
      m_SQLConnection.Free;
    end;
  end;  

begin
  Console := CoConsole.CreateInstance;
  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('This program demonstrates how to use ClrObject interface to connect to Sql Server.');
  Console.WriteLine;
  try
    TClrAssembly.LoadWithPartialName('System.Data');

    Console.WriteLine_15('The Assembly [{0}] has been loaded.', 'System.Data');
    Console.WriteLine;

    //Create Instance of System.Data.SqlClient.SqlConnection Type
    SQLConnection := TClrDispatchActivator.CreateInstance('System.Data.SqlClient.SqlConnection');

    ConnectionString := 'Data Source=myServerAddress;Initial Catalog=myDataBase;User ID=myUsername;Password=myPassword;';
    Console.WriteLine_15('Connecting to : {0}', ConnectionString);
    Console.WriteLine;

    CreateClrObjectUsingWrap;
    CreateClrObjectUsingTClrObjectClass;
  except
    on E: Exception do
      Console.WriteLine_15('Exception: {0}', E.Message);
  end;
  Console.ReadKey;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Collections\Other Examples\Collections.dpr program Collections;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils,
{$ELSE}
  SysUtils,
{$IFEND }
  CNClrLib.Host, CNClrLib.Core, CNClrLib.Collections,
  CNClrLib.TypeNames, CNClrLib.Host.Helper;

var
  Console: _Console;
  NamesArray : _StringArray;
  NamesEnumerator: _IEnumerator;
  ArrayList: _ArrayList;
  StringList: _StringCollection;
  StringDictionary: _StringDictionary;
  StringDictValuesEnumerator: _IEnumerator;
  SortedListValuesEnumerator: _IEnumerator;
  HashTableKeysEnumerator: _IEnumerator;
  AEnumerator: _IEnumerator;
  Stack: _Stack;
  Queue: _Queue;
  BitArray: _BitArray;
  HashTable: _Hashtable;
  SortedList: _SortedList;
  I, P: Integer;

begin
  try
    Console := CoConsole.CreateInstance;

    //========================================================================
    //                    Using _IEnumerable Interface
    //========================================================================
    //An enumerator is an object that provides a forward, read-only cursor for a set of items.
    //The _IEnumerable interface has one method called the GetEnumerator method.
    //This method returns an object that implements the IEnumerator interface.
    //The code snippet below illustrates how an enumerator can be used to iterate
    //though a list or collection of items.

    NamesArray := CoStringArray.CreateInstance(2);
    NamesArray[0] := 'Joydip';
    NamesArray[1] := 'Jini';
    NamesEnumerator := NamesArray.AsIEnumerator;
    while NamesEnumerator.MoveNext do
      Console.WriteLine_12(NamesEnumerator.Current);

    //Note that the GetEnumerator method returns an enumerator object each time it is called.
    //Further, the loop contains the Console.WriteLine_12 statement in its re-initializer portion,
    //which is perfectly valid. The condition being evaluated is whether the MoveNext method
    //returns a value of true. The MoveNext method returns true as long as there are items in
    //the collection. The Current property returns the current object and is automatically typecast
    //to string by making a call to the ToString method implicitly.


    //========================================================================
    //                        Using _ArrayList Interface
    //========================================================================
    //The _ArrayList interface is a dynamic array of heterogeneous objects. Note that in an array
    //we can store only objects of the same type. In an ArrayList, however, we can have different
    //type of objects; these in turn would be stored as object type only.  We can have an ArrayList
    //object that stores integer, float, string, etc., but all these objects would only be stored as
    //object type. An ArrayList uses its indexes to refer to a particular object stored in its collection.
    //The Count property gives the total number of items stored in the ArrayList object.
    //The Capacity property gets or sets the number of items that the ArrayList object can contain.
    //Objects are added using the Add method of the ArrayList and removed using its Remove method.
    //An example of usage of an ArrayList is given below.

    ArrayList := CoArrayList.CreateInstance;
    ArrayList.Add('Joydip');
    ArrayList.Add(100);
    ArrayList.Add(20.5);
    for I := 0 to ArrayList.Count - 1 do
      Console.WriteLine_12(ArrayList[I]);

    //It is to be noted here that the initial capacity of an ArrayList is 16, which is increased once the
    //17th item is stored onto it. This repeated memory allocation and copying of the items can be quite
    //expensive in some situations. For performance reasons we can set the initial capacity of the object
    //of an ArrayList by using the Capacity property or an overloaded constructor of the ArrayList class.
    //This is shown in the example below.

    ArrayList := CoArrayList.CreateInstance;
    ArrayList.Capacity := 3;
    ArrayList.Add('Joydip');
    ArrayList.Add(100);
    ArrayList.Add(20.5);
    for I := 0 to ArrayList.Count - 1 do
      Console.WriteLine_12(ArrayList[I]);


    //========================================================================
    //                  Using _StringCollection Interface
    //========================================================================
    //The StringCollection interface implements the IList interface and is like an ArrayList of strings.
    //The following code example shows how we can work with a StringCollection class.

    StringList := CoStringCollection.CreateInstance;
    StringList.Add('Manashi');
    StringList.Add('Joydip');
    StringList.Add('Jini');
    StringList.Add('Piku');

    for I := 0 to StringList.Count - 1 do
      Console.WriteLine_14(StringList[I]);


    //========================================================================
    //                 Using _StringDictionary Interface
    //========================================================================
    //Similar to the StringCollection interface we have the StringDictionary interface,
    //which is just a Hashtable that has its keys as strings only. Remember that a Hashtable
    //can contain any object type in its key. The following code shows how we can work with a
    //StringDictionary interface.

    StringDictionary := CoStringDictionary.CreateInstance;
    StringDictionary.Add('A', 'Manashi');
    StringDictionary.Add('B','Joydip');
    StringDictionary.Add('C','Jini');
    StringDictionary.Add('D','Piku');

    StringDictValuesEnumerator := StringDictionary.Values.AsIEnumerable.GetEnumerator;
    while StringDictValuesEnumerator.MoveNext do
      Console.WriteLine_14(StringDictValuesEnumerator.Current);


    //========================================================================
    //                        Using _Stack Interface
    //========================================================================
    //The _Stack interface is one that provides a Last-in-First-out (LIFO) collection of items
    //of the System.Object type. The last added item is always at the top of the Stack and is also
    //the first one to be removed. The following code sample shows how we can use a Stack class for
    //LIFO operation on its collection of items.

    Stack := CoStack.CreateInstance;
    Stack.Push('Joydip');
    Stack.Push('Steve');
    Stack.Push('Jini');
    while (Stack.Count > 0) do
      Console.WriteLine_12(Stack.Pop);

    //The Push method is responsible for storing items in the Stack and the method Pop
    //removes them one at a time from the top of the Stack.


    //========================================================================
    //                   Using _Queue Interface
    //========================================================================
    //Unlike the Stack interface, the Queue is a data structure that provides a First-in-First-out
    //collection of items of the Object type. The newly added items are stored at the end or
    //the rear of the Queue and items are deleted from the front of the Queue.
    //The following code shows how the Queue class can be used.

    Queue := CoQueue.CreateInstance;
    Queue.Enqueue('Joydip');
    Queue.Enqueue('Steve');
    Queue.Enqueue('Jini');
    while (Queue.Count > 0) do
      Console.WriteLine_12(Queue.Dequeue);

    //The Enqueue method is responsible for storing items at the rear of the Queue and the method Dequeue
    //removes them one at a time from the front of the Queue.


    //========================================================================
    //                     Using _BitArray Interface
    //========================================================================
    //The BitArray interface can be used to store bits in an array. They can be set to true or false,
    //depending on the parameter supplied at the time of creating the BitArray object.
    //The following is an example of its usage.

    BitArray := CoBitArray.CreateInstance(5, false);
    // Or
    BitArray := CoBitArray.CreateInstance(5, true);
    // Similar to the other collections discussed above, the BitArray interface also contains the
    //Count property to get the number of items stored in this collection of bit values.
    //The following methods of the BitArray class allow logical bit operation.
    // ·         And
    // ·         Or
    // ·         Not
    // ·         Xor



    //========================================================================
    //                     Using _Hashtable Interface
    //========================================================================
    //The Hashtable provides a faster way of storage and retrieval of items of the object type.
    //The Hashtable class provides support for key based searching. These keys are unique hash codes that
    //are unique to a specific type.  The GetHashCode method of the Hashtable class returns the hash code
    //for an object instance. The following code snippet shows how we can use a Hashtable interface.

    HashTable := CoHashtable.CreateInstance;
    HashTable.Add(1, 'Joydip');
    HashTable.Add(2, 'Manashi');
    HashTable.Add(3, 'Jini');
    HashTable.Add(4, 'Piku');
    Console.WriteLine_14('The keys are:--');
    HashTableKeysEnumerator := HashTable.Keys.AsIEnumerable.GetEnumerator;
    while HashTableKeysEnumerator.MoveNext do
      Console.WriteLine_12(HashTableKeysEnumerator.Current);

    try
      Console.WriteLine_14('Please enter the key to search');
      p := TClrInt32Helper.Parse(Console.ReadLine);
      Console.WriteLine_12(HashTable[p]);
    except
      on E: Exception do
        Console.WriteLine_12(E.Message);
    end;

    //To remove an item from the Hashtable interface, the Remove method is used.
    //The statement HashTable.Remove(3) would remove the item "Jini" from the Hashtable
    //object created in the above code.  The code shown above can also be written as shown below
    //to display the contents of the Hashtable object using IDictionaryEnumerator.

    HashTable := CoHashtable.CreateInstance;
    HashTable.Add(1, 'Joydip');
    HashTable.Add(2, 'Manashi');
    HashTable.Add(3, 'Jini');
    HashTable.Add(4, 'Piku');
    Console.WriteLine_14('The keysare:--');
    AEnumerator := HashTable.GetEnumerator.AsIEnumerator;
    while AEnumerator.MoveNext do
      Console.WriteLine_12(HashTable[p]);


    //========================================================================
    //                     Using _SortedList Interface
    //========================================================================
    //The _SortedList interface allows items of the Object type to be placed in the
    //collection using key value pairs and, at the same time, supports sorting.
    //The following code shows how we can use a SortedList.

    SortedList := CoSortedList.CreateInstance;
    SortedList.Add(1, 'Manashi');
    SortedList.Add(3, 'Joydip');
    SortedList.Add(2, 'Jini');
    SortedList.Add(4, 'Piku');

    Console.WriteLine_14('Displaying thenames');

    SortedListValuesEnumerator:= SortedList.Values.AsIEnumerable.GetEnumerator;
    while SortedListValuesEnumerator.MoveNext do
      Console.WriteLine_14(SortedListValuesEnumerator.Current);

    //The output of the above code is:
    //  Manashi
    //  Jini
    //  Joydip
    //  Piku

    //The same code can be written using IDictionaryEnumerator to display all the items of the
    //SortedList object, as shown below.

    SortedList := CoSortedList.CreateInstance;
    SortedList.Add(1, 'Manashi');
    SortedList.Add(3, 'Joydip');
    SortedList.Add(2, 'Jini');
    SortedList.Add(4, 'Piku');
    Console.WriteLine_14('Displaying thenames');
    AEnumerator := SortedList.Values.AsIEnumerable.GetEnumerator;
    while AEnumerator.MoveNext do
      Console.WriteLine_12(AEnumerator.Current);

    Console.ReadKey;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Collections\Generic Dictionary\GenericDictionary.dpr program GenericDictionary;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils,
{$ELSE}
  SysUtils,
{$IFEND }
  CNClrLib.Host,
  CNClrLib.Core,
  CNClrLib.Collections;

var
  OpenWith: _GenericDictionary;
  OpenWithEnumerator: _GenericDictionary_Enumerator;
  ValueCollection: _GenericDictionary_ValueCollection;
  ValueCollEnumerator: _GenericValueCollection_Enumerator;
  keyCollection: _GenericDictionary_KeyCollection;
  keyCollEnumerator: _GenericKeyCollection_Enumerator;
  Console: _Console;
  Value: OleVariant;
begin
  try
    Console := CoConsole.CreateInstance;

    // Create a new dictionary of strings, with string keys.
    OpenWith := CoGenericDictionary.CreateInstance(TClrAssembly.GetType('System.String'),
      TClrAssembly.GetType('System.String'));

    // Add some elements to the dictionary. There are no
    // duplicate keys, but some of the values are duplicates.
    OpenWith.Add('txt', 'notepad.exe');
    OpenWith.Add('bmp', 'paint.exe');
    OpenWith.Add('dib', 'paint.exe');
    OpenWith.Add('rtf', 'wordpad.exe');

    // The Add method throws an exception if the new key is
    // already in the dictionary.
    try
      OpenWith.Add('txt', 'winword.exe');
    except //(ArgumentException)
      Console.WriteLine_14('An element with Key = ''txt'' already exists.');
    end;

    // The Item property is another name for the indexer, so you
    // can omit its name when accessing elements.
    Console.WriteLine_15('For key = ''rtf'', value = {0}.', OpenWith['rtf']);

    // The indexer can be used to change the value associated
    // with a key.
    OpenWith['rtf'] := 'winword.exe';
    Console.WriteLine_15('For key = ''rtf'', value = {0}.', OpenWith['rtf']);

    // If a key does not exist, setting the indexer for that key
    // adds a new key/value pair.
    OpenWith['doc'] := 'winword.exe';

    // The indexer throws an exception if the requested key is
    // not in the dictionary.
    try
      Console.WriteLine_15('For key = ''tif'', value = {0}.', OpenWith['tif']);
    except //(KeyNotFoundException)
      Console.WriteLine_14('Key = ''tif'' is not found.');
    end;

    // When a program often has to try keys that turn out not to
    // be in the dictionary, TryGetValue can be a more efficient
    // way to retrieve values.
    if (OpenWith.TryGetValue('tif', Value)) then
      Console.WriteLine_15('For key = ''tif'', value = {0}.', Value)
    else
      Console.WriteLine_14('Key = ''tif'' is not found.');

    // ContainsKey can be used to test keys before inserting them.
    if (not OpenWith.ContainsKey('ht')) then
    begin
      OpenWith.Add('ht', 'hypertrm.exe');
      Console.WriteLine_15('Value added for key = ''ht'': {0}', OpenWith['ht']);
    end;

    // When you use when loop to enumerate dictionary elements from GetEnumerator,
    // the elements are retrieved as KeyValuePair objects.
    Console.WriteLine();
    OpenWithEnumerator := OpenWith.GetEnumerator;
    while OpenWithEnumerator.MoveNext do
      Console.WriteLine_17('Key = {0}, Value = {1}', OpenWithEnumerator.Current.Key, OpenWithEnumerator.Current.Value);

    // To get the values alone, use the Values property.
    ValueCollection := OpenWith.Values;
    ValueCollEnumerator := ValueCollection.GetEnumerator;

    // The elements of the ValueCollection are strongly typed
    // with the type that was specified for dictionary values.
    Console.WriteLine();
    while ValueCollEnumerator.MoveNext do
      Console.WriteLine_15('Value = {0}', ValueCollEnumerator.Current);

    // To get the keys alone, use the Keys property.
    keyCollection := OpenWith.Keys;
    keyCollEnumerator := keyCollection.GetEnumerator;

    // The elements of the KeyCollection are strongly typed
    // with the type that was specified for dictionary keys.
    Console.WriteLine();
    while keyCollEnumerator.MoveNext do
      Console.WriteLine_15('Key = {0}', keyCollEnumerator.Current);

    // Use the Remove method to remove a key/value pair.
    Console.WriteLine_14('Remove(''doc'')');
    OpenWith.Remove('doc');

    if (not OpenWith.ContainsKey('doc')) then
      Console.WriteLine_14('Key ''doc'' is not found.');

    Console.ReadKey;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Event Handler\Standard\EventHandling.dpr program EventHandling;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils, System.Variants,
{$ELSE}
  SysUtils, Variants,
{$IFEND }
  CNClrLib.Host, CNClrLib.Core;

var
  Console : _Console;
  SQLConnection : TClrObject;
  ConnectionString : WideString;
  
(*
  //C# Delegate of SqlConnection.StateChange event
  
  public delegate void StateChangeEventHandler(object sender, StateChangeEventArgs e);

  public enum ConnectionState
  {
      Closed = 0,
      Open = 1,
      Connecting = 2,
      Executing = 4,
      Fetching = 8,
      Broken = 16,
  }

  public sealed class StateChangeEventArgs
  {
      public ConnectionState CurrentState { get; }
      public ConnectionState OriginalState { get; }
  }
*)

  //Corresponding Delphi Event Handler Callback method
  procedure StateChangeEventHandler(ASender : _ClrObject; StateChangeEventArgs : _ClrEventArgs); stdcall;
  var
    m_eventArgs : _ClrObject;
    m_currentState,
    m_originalState : Integer;

    procedure WriteStateChage(State : Integer);
    begin
      case State of
        0:  Console.Write_22('Closed');
        1:  Console.Write_22('Open');
        2:  Console.Write_22('Connecting');
        4:  Console.Write_22('Executing');
        8:  Console.Write_22('Fetching');
        16: Console.Write_22('Broken');
      end;
      Console.WriteLine;
    end;
  begin
    m_eventArgs :=  CoClrObject.Wrap(StateChangeEventArgs.EventArgs);
    m_currentState := m_eventArgs.GetPropertyValue('CurrentState');
    m_originalState := m_eventArgs.GetPropertyValue('OriginalState');

    Console.Write_22('Current State : ');
    WriteStateChage(m_currentState);

    Console.Write_22('Original State : ');
    WriteStateChage(m_originalState);
  end;

  procedure OpenAndCloseSQLConnection;
  begin
    SQLConnection.SetPropertyValue('ConnectionString', ConnectionString);

    SQLConnection.InvokeMethod('Open');
    Console.WriteLine_14('Connection Opened');

    SQLConnection.InvokeMethod('Close');
    Console.WriteLine_14('Connection Closed');
  end;

begin
  Console := CoConsole.CreateInstance;

  Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
  Console.WriteLine_14('==================================================');
  Console.WriteLine_14('This program demonstrates how to handle events and callback.');
  Console.WriteLine;
  try
    //Load Assembly
    TClrAssembly.LoadWithPartialName('System.Data');

    //Create Instance of System.Data.SqlClient.SqlConnection Type
    SQLConnection := TClrObject.Create(TClrActivator.ClrCreateInstance('System.Data.SqlClient.SqlConnection'));
    SQLConnection.RegisterEventCallBack('StateChange', @StateChangeEventHandler);
    try
      ConnectionString := 'Data Source=myServerAddress;Initial Catalog=myDataBase;User ID=myUsername;Password=myPassword';
      Console.WriteLine_15('Connecting to : {0}', ConnectionString);
      Console.WriteLine;

      OpenAndCloseSQLConnection;
    finally
      SQLConnection.Free;
    end;
  except
    on E: Exception do
      Console.WriteLine_15('Exception: {0}', E.Message);
  end;
  Console.ReadKey;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Event Handler\Advanced\AdvancedEventHandler.dpr program AdvancedEventHandler;

{$APPTYPE CONSOLE}
{$R *.res}

uses
{$IF CompilerVersion > 22}
  System.SysUtils, System.Variants,
{$ELSE}
  SysUtils, Variants,
{$IFEND }
  CNClrLib.Host, CNClrLib.Core;

type

  TEventHandler = class
  private
    FSQLConnection : TClrObject;
    FConnectionStr : WideString;

    FEventHandler : TClrEventHandler;
    procedure SetOnStateChangeEvent(Value : TClrEventHandler);
  public
    constructor Create;
    destructor Destroy; override;
    procedure LoadAssembly;
    procedure CreateSQLConnectionTypeInstance;
    procedure EventFired;
    procedure OpenAndCloseSQLConnection;
    property OnStateChangeEvent : TClrEventHandler read FEventHandler write SetOnStateChangeEvent;
  end;
  
var
  Console : _Console;
  EventHandler : TEventHandler;


  { TEventHandler }

  constructor TEventHandler.Create;
  begin
  end;

  destructor TEventHandler.Destroy;
  begin
    FSQLConnection := Nil;
    inherited Destroy;
  end;

  procedure TEventHandler.EventFired;
  begin
    Console.WriteLine_14('State Change Event has been fired');
  end;

  procedure TEventHandler.LoadAssembly;
  begin
    //Load Assembly
    TClrAssembly.LoadWithPartialName('System.Data');
  end;

  procedure TEventHandler.CreateSQLConnectionTypeInstance;
  begin
    //Create Instance of System.Data.SqlClient.SqlConnection Type
    FSQLConnection := TClrObject.Create(TClrDispatchActivator.CreateInstance('System.Data.SqlClient.SqlConnection'));
  end;

  procedure TEventHandler.OpenAndCloseSQLConnection;
  begin
    FConnectionStr := 'Data Source=MyDataSourceName;Initial Catalog=MyDBName;User ID=MyUserName;Password=MyPasswd';

    Console.WriteLine_15('Connecting to SQL Connection using : {0}', FConnectionStr);
    Console.WriteLine;

    FSQLConnection.SetPropertyValue('ConnectionString', FConnectionStr);

    FSQLConnection.InvokeMethod('Open');
    Console.WriteLine_14('Connection Opened');
    Console.WriteLine;

    FSQLConnection.InvokeMethod('Close');
    Console.WriteLine_14('Connection Closed');
  end;

  procedure TEventHandler.SetOnStateChangeEvent(Value: TClrEventHandler);
  begin
    if @FEventHandler <> nil then
      FSQLConnection.UnRegisterEventCallBack('StateChange', @FEventHandler);

    FEventHandler := Value;

    if @FEventHandler <> nil then
      FSQLConnection.RegisterEventCallBack('StateChange', @FEventHandler);
  end;

  (*
    //C# Delegate of SqlConnection.StateChange event
    public delegate void StateChangeEventHandler(object sender, StateChangeEventArgs e);
  
    public enum ConnectionState
    {
        Closed = 0,
        Open = 1,
        Connecting = 2,
        Executing = 4,
        Fetching = 8,
        Broken = 16,
    }
    public sealed class StateChangeEventArgs
    {
        public ConnectionState CurrentState { get; }
        public ConnectionState OriginalState { get; }
    }
  *)

  //Corresponding Delphi Event Handler Caller method
  procedure StateChangeEventHandler(ASender : _ClrObject; StateChangeEventArgs : _ClrEventArgs); stdcall;
  var
    m_eventArgs : _ClrObject;
    m_currentState,
    m_originalState : Integer;

    procedure WriteStateChage(State : Integer);
    begin
      case State of
        0:  Console.Write_22('Closed');
        1:  Console.Write_22('Open');
        2:  Console.Write_22('Connecting');
        4:  Console.Write_22('Executing');
        8:  Console.Write_22('Fetching');
        16: Console.Write_22('Broken');
      end;
      Console.WriteLine;
    end;
  begin
    m_eventArgs :=  CoClrObject.Wrap(StateChangeEventArgs.EventArgs);
    m_currentState := m_eventArgs.GetPropertyValue('CurrentState');
    m_originalState := m_eventArgs.GetPropertyValue('OriginalState');

    Console.Write_22('Current State : ');
    WriteStateChage(m_currentState);
    Console.Write_22('Original State : ');
    WriteStateChage(m_originalState);
  end;

begin
  Console := CoConsole.CreateInstance;
  EventHandler := TEventHandler.Create;
  try
    Console.WriteLine_14('Hello! Welcome to .Net Runtime Library for Delphi.');
    Console.WriteLine_14('==================================================');
    Console.WriteLine_14('This program demonstrates how to handle events and get '+
                          'Delphi class type which added the event.');
    Console.WriteLine;
    try
      with EventHandler do begin
        LoadAssembly;
        CreateSQLConnectionTypeInstance;
        OnStateChangeEvent := StateChangeEventHandler; 
        OpenAndCloseSQLConnection; 
      end;  
    except
      on E: Exception do
        Console.WriteLine_15('Exception: {0}', E.Message);
    end;  
    Console.ReadKey;
  finally
    FreeAndNil(EventHandler);
  end;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\XML\XML.dpr program XML;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  CNClrLib.Xml,
  CNClrLib.Core;

var
  NameTable: _NameTable;
  Book, Price: Variant;
  Settings: _XmlReaderSettings;
  Reader: _XmlReader;
  ReaderHelper: _XmlReaderHelper;
  ObjectHelper: _ObjectHelper;
begin
  NameTable := CoNameTable.CreateInstance;

  Book := NameTable.Add('Book');
  Price := NameTable.Add('Price');

  // Create the Reader.
  Settings := CoXmlReaderSettings.CreateInstance;
  Settings.NameTable := NameTable.AsXmlNameTable;

  ReaderHelper := CoXmlReaderHelper.CreateInstance;
  Reader := ReaderHelper.Create_1('books.xml', Settings);

  Reader.MoveToContent;
  Reader.ReadToDescendant('Book');

  ObjectHelper := CoObjectHelper.CreateInstance;
  if ObjectHelper.ReferenceEquals(Book, Reader.Name) then
  begin
    // Do additional processing.
  end;
end.
C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Diagnostics\Diagnostics.dpr program Diagnostics;

{$WARN SYMBOL_PLATFORM OFF}
{$APPTYPE CONSOLE}
{$R *.res}

//  The following example uses Trace to indicate the beginning and the end of a program's execution.
//  The example also uses the Trace.Indent and Trace.Unindent methods to distinguish the tracing output.

uses
  SysUtils,
  CNClrLib.Diagnostics,
  CNClrLib.Core;

var
  Console: _Console;
  Trace: _Trace;
begin
  try
    Console := CoConsole.CreateInstance;

    Trace := CoTrace.CreateInstance;
    Trace.Listeners.Add(CoTextWriterTraceListener.CreateInstance(Console.Out_).AsTraceListener);
    Trace.AutoFlush := true;
    Trace.Indent;
    Trace.WriteLine('Entering Main');
    Console.WriteLine_14('Hello World.');
    Trace.WriteLine('Exiting Main');
    Trace.Unindent;
  except
    on E: Exception do
    begin
      Console.WriteLine_14(E.message);
    end;
  end;
end.

C:\CrystalNet\DotNet Runtime Library for Delphi\ClrHostLibrary\Demo\Security\RijndaelSecurity.dpr program RijndaelSecurity;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  CNClrLib.EnumTypes,
  CNClrLib.Host,
  CNClrLib.Core;

function EncryptStringToBytes(plainText: string; Key, IV: _ByteArray): _ByteArray;
var
  rijAlg: _RijndaelManaged;
  encryptor: _ICryptoTransform;
  msEncrypt: _MemoryStream;
  csEncrypt: _CryptoStream;
  swEncrypt: _StreamWriter;
begin
  // Check arguments.
  if plainText.Length <= 0 then
    raise Exception.Create('plainText argument is empty');

  if (Key = nil) or (Key.Length <= 0) then
    raise Exception.Create('Key argument is empty or nil');

  if (IV = nil) or (IV.Length <= 0) then
    raise Exception.Create('IV argument is empty or nil');

  // Create an RijndaelManaged object with the specified key and IV.
  rijAlg := CoRijndaelManaged.CreateInstance;
  rijAlg.Key := Key;
  rijAlg.IV := IV;

  // Create a decrytor to perform the stream transform.
  encryptor := rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

  // Create the streams used for encryption.
  msEncrypt := CoMemoryStream.CreateInstance;
  csEncrypt := CoCryptoStream.CreateInstance(msEncrypt.AsStream, encryptor, csmWrite);

  swEncrypt := coStreamWriter.CreateInstance(csEncrypt.AsStream);
  //Write all data to the stream.
  swEncrypt.Write_3(plainText);
  swEncrypt.Close;

  // Return the encrypted bytes from the memory stream.
  result := msEncrypt.ToArray;
  msEncrypt.Close;
  csEncrypt.Close;
  swEncrypt.Close;
end;

function DecryptStringFromBytes(cipherText, Key, IV: _ByteArray): string;
var
  rijAlg: _RijndaelManaged;
  decryptor: _ICryptoTransform;
  msDecrypt: _MemoryStream;
  csDecrypt: _CryptoStream;
  srDecrypt: _StreamReader;
begin
  // Check arguments.
  if (cipherText = nil) or (cipherText.Length <= 0) then
    raise Exception.Create('cipherText argument is empty or nil');

  if (Key = nil) or (Key.Length <= 0) then
    raise Exception.Create('Key argument is empty or nil');

  if (IV = nil) or (IV.Length <= 0) then
    raise Exception.Create('IV argument is empty or nil');

  // Create an RijndaelManaged object
  // with the specified key and IV.
  rijAlg := CoRijndaelManaged.CreateInstance;
  rijAlg.Key := Key;
  rijAlg.IV := IV;

  // Create a decrytor to perform the stream transform.
  decryptor := rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

  // Create the streams used for decryption.
  msDecrypt := CoMemoryStream.CreateInstance(cipherText);

  csDecrypt := CoCryptoStream.CreateInstance(msDecrypt.AsStream, decryptor, csmRead);

  srDecrypt := CoStreamReader.CreateInstance(csDecrypt.AsStream);

  // Read the decrypted bytes from the decrypting stream and place them in a string.
  result := srDecrypt.ReadToEnd;

  msDecrypt.Close;
  csDecrypt.Close;
  srDecrypt.Close;
end;


var
  key: Char;
  original,
  roundtrip: string;
  myRijndael: _RijndaelManaged;
  encrypted: _ByteArray;
begin
  try
    original := 'Here is some data to encrypt!';

    // Create a new instance of the RijndaelManaged
    // class.  This generates a new key and initialization
    // vector (IV).
    myRijndael := CoRijndaelManaged.CreateInstance;
    myRijndael.GenerateKey;
    myRijndael.GenerateIV;

    // Encrypt the string to an array of bytes.
    encrypted := EncryptStringToBytes(original, myRijndael.Key, myRijndael.IV);

    // Decrypt the bytes to a string.
    roundtrip := DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);

    //Display the original data and the decrypted data.
    Writeln('Original:   %s', original);
    Writeln('Round Trip: %s', roundtrip);

    Writeln('Press any key to continue.....');
    Readln(key);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

To access the full source code examples, kindly download the Compiled demo zip file from the Download Page.