Software Developer, Technology Enthusiast, Retro and Husband and Dad based in Melbourne.

Delphi and .NET Interop with JVCL

There are different methods for Delphi to communicate with the .NET Framework:

  • Commercial projects e.g. Remobjects Hydra, Atozed CrossTalk and Managed VCL etc.
  • Importing .NET Assembly using the Import Component Wizard.
  • Or Open Source method using JVCL.

Why choose JVCL over the commercial projects and the Import Component Wizard which is part of Delphi?

  • Open Source e.g. free as in beer.
  • Independent of regasm.exe which registers Class Libraries into the Global Assemble Cache (GAC)

How does JclDotNet work?

JVCL provides communication to the .NET Framework using the JclDotNet unit, by providing variant based
late bound automation to the .NET class library.

This post will provide two examples by stepping through each part, which should provide a basic grounding on how the 
JVCL JclDotNet unit communicates with .NET Framework.

For these examples your Delphi must have JVCL 3.45 or higher installed and for  the C# Class Library .NET 4.5 Framework
 (Visual Studio 2012).

Example 1

This example demonstrates a basic adding of two numbers together, by calling the C# class library Example1ClassLibrary.DLL

Delphi Example
  • To start the TJclClrHost class must initialize a .NET Framework – Common Language Runtime (CLR) and start the host:
Host := TJclClrHost.Create('v4.0.30319');
Host.Start();
  • NOTE: By default if you leave the ClrVer variable blank, it defaults to v2.0.50727.
Host := TJclClrHost.Create;
  • For this example we will be using CLR v4.0.30319 which supports either .NET 4.5 or .NET 4 Framework.
  • C# Class Library must now be initialize and Obj: OleVariant for the access to method:
Obj := Host.DefaultAppDomain
.CreateInstance('Example1ClassLibrary' {.NET Assemble Name},

'Example1ClassLibrary.Example1' {Namespace.Classname})

.UnWrap();
  • First part is the name of .NET Assemble File ‘Example1ClassLibrary.dll’.
  • ‘Example1ClassLibrary.Example1‘ next part is the namespace and the classname
  • Accessing this method from the C# Class Library as simple has keeping the name and the parameters the same as the class library:
Result := Obj.AddFunction(aXValue, aYValue);
  • Release the CLR host just stop and free the TJclClrHost class:
Host.Stop();
Host.Free;
Full Function
function TfrmMain.AddFunction(aXValue: Integer; aYValue:Integer): Integer;
var
  Host: TJclClrHost;
  Obj: OleVariant;
begin
  try
    Host := TJclClrHost.Create('v4.0.30319');
    Host.Start();

    Obj := Host.DefaultAppDomain
        .CreateInstance('Example1ClassLibrary',
        'Example1ClassLibrary.Example1')
        .UnWrap();

     Result := Obj.AddFunction(aXValue, aYValue);

    Host.Stop();
    Host.Free;
  Except
     on E : Exception do
     begin
       ShowMessage('Exception class name = '+E.ClassName + ' ' + 'Exception message = '+E.Message);
     end;
  end;
end;

C# Class Library

Some basic setting up of example 1 Class Library allowing Delphi work with Interop Services:

  • Include in your namespace for the Interop Services
using System.Runtime.InteropServices;
  • To expose the class to COM access to Delphi
[ComVisible(true)]
public class Example1
  • All functions must be public
public int AddFunction(int aXValue, int aYValue)
{
return aXValue + aYValue;
}
Class Library
namespace Example1ClassLibrary
{
    [ComVisible(true)]
    public class Example1
    {
        public int AddFunction(int aXValue, int aYValue)
        {
            return aXValue + aYValue;
        }
    }
}

Example 2

In this example we take the basic adding of two numbers together and expand out how Delphi can access the Example2ClassLibrary.DLL using the mscorlib_TLB import library:

Delphi Example
uses
mscorlib_TLB, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,? StdCtrls, JclDotNet;
  • NOTE: mscorlib_TLB should be the first unit.
  • Initializing the host to .NET Framework in the formcreate event:
procedure TfrmMain.FormCreate(Sender: TObject);
begin
   FClrHost := TJclClrHost.Create('v4.0.30319');

   FClrHost.Start;
end;
  • Setup the access to the Class Library path and application:
Fads.ApplicationBase := '..\Example2\Debug\Win32\';
Fad := FClrHost.CreateAppDomain('myNET', Fads);
  • NOTE: CreateAppDomain(‘myNET’ should be a different name if two or more a being called.
  • The C# Class Library must now be initialize and Obj: OleVariant for the access to the method:
obj := (Fad as _AppDomain).CreateInstanceFrom('Example2ClassLibrary.dll',
     'Example2ClassLibrary.Example2');
ov := obj.Unwrap;result := ov.AddFunction(aXValue, aYValue);
  • To release the CLR host just stop and free has been setup on the FormDestory event:
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  FClrHost.Stop();
  FClrHost.Free;
end;
Full Function
function TfrmMain.AddFunction(aXValue: Integer; aYValue:Integer): Integer;
var
  Fads: TJclClrAppDomainSetup;
  Fad: TJclClrAppDomain;
  Ov: OleVariant;
  obj: _ObjectHandle;
begin
  try
    Fads := FClrhost.CreateDomainSetup;

    Fads.ApplicationBase := '..\Example2\Debug\Win32\';
    Fad := FClrHost.CreateAppDomain('myNET', Fads);
    obj := (Fad as _AppDomain).CreateInstanceFrom('Example2ClassLibrary.dll',
         'Example2ClassLibrary.Example2');
    ov := obj.Unwrap;
    result := ov.AddFunction(aXValue, aYValue);
  except
    on E : Exception do
     begin
       ShowMessage('Exception class name = '+E.ClassName +
          ' ' + 'Exception message = '+E.Message);     end;
  end;
end;

Download Examples

https://github.com/acj1971/DelphiDotNETInteropJVCLExamples

Links

JVCL
http://jvcl.delphi-jedi.org/

.NET 4.5 Framework
http://www.microsoft.com/en-au/download/details.aspx?id=30653

Common Language Runtime (CLR)
http://msdn.microsoft.com/en-us/library/8bs2ecf4.aspx

Remobjects Hydra
http://www.remobjects.com/hydra/

Atozed CrossTalk
http://www.atozed.com/CrossTalk/index.en.aspx

Managed VCL
http://www.managed-vcl.com/

Import Component Wizard
http://docwiki.embarcadero.com/RADStudio/XE3/en/Import_Component_Wizard