Source Code Examples

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.

Eg.1: How to write a simple Hello World using .Net Console

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.

Eg.2: How to use AppDomain to Load .Net Assemblies

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.

Eg.3: How to use Activator to Create instance of a .Net Object

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.

Eg.4: How to use Dispatch Activator to Create instance of a .Net Object as Dispatch Interface

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.

Eg.5: How to load external .Net DLL and access the members of loaded assembly types

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.


Eg.6: How to use ClrObject interface to connect to SQL Server

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.

Eg.7: How to use .Net Collections in Delphi

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.

Eg.8: How to use .Net Generic Dictionary in Delphi

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.

Eg.9: How to raise and handle .Net Events in Delphi 1

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.

Eg.10: How to raise and handle .Net Events in Delphi 2

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.

Eg.11: How to use .Net XML Classes to compare two element names

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.

Eg.12: How to use .Net Trace in delphi to indicate the beginning and the end of a program's execution

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.

Eg.13: How to encrypt and decrypt sample data using the .Net RijndaelManaged

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.

Eg.14: How to use .Net XML Classes to compare two element names in Delphi

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.