Hosting Clr in Delphi With/Without Jcl - Example

Hosting CLR in Delphi with/without JCL - example

The class has to be comvisible. Which might not be the case if you have ComVisible(false) for the whole assembly.

.Net classes will be IDispatch compatible by default, so your sample should work just fine, if the class really is comvisible..

But strip it down to the bare minimum first. Put your exe in the same folder as your .Net assembly and skip the config file and application base.

Before something gets mixed up, the exception happesn here, right?

 ov := obj.Unwrap;

Hosting the .NET runtime in a Delphi Program

In the Jedi Code Library (JCL) - free - there is a JclDotNet.pas, containing a class TJclClrHost, probably doing what you want:

  TJclClrHost = class(TJclClrBase, ICorRuntimeHost)
private
FDefaultInterface: ICorRuntimeHost;
FAppDomains: TObjectList;
procedure EnumAppDomains;
function GetAppDomain(const Idx: Integer): TJclClrAppDomain;
function GetAppDomainCount: Integer;
function GetDefaultAppDomain: IJclClrAppDomain;
function GetCurrentAppDomain: IJclClrAppDomain;
protected
function AddAppDomain(const AppDomain: TJclClrAppDomain): Integer;
function RemoveAppDomain(const AppDomain: TJclClrAppDomain): Integer;
public
constructor Create(const ClrVer: WideString = '';
const Flavor: TJclClrHostFlavor = hfWorkStation;
const ConcurrentGC: Boolean = True;
const LoaderFlags: TJclClrHostLoaderFlags = [hlOptSingleDomain]);
destructor Destroy; override;
procedure Start;
procedure Stop;
procedure Refresh;
function CreateDomainSetup: TJclClrAppDomainSetup;
function CreateAppDomain(const Name: WideString;
const Setup: TJclClrAppDomainSetup = nil;
const Evidence: IJclClrEvidence = nil): TJclClrAppDomain;
function FindAppDomain(const Intf: IJclClrAppDomain; var Ret: TJclClrAppDomain): Boolean; overload;
function FindAppDomain(const Name: WideString; var Ret: TJclClrAppDomain): Boolean; overload;
class function CorSystemDirectory: WideString;
class function CorVersion: WideString;
class function CorRequiredVersion: WideString;
class procedure GetClrVersions(VersionNames: TWideStrings); overload;
class procedure GetClrVersions(VersionNames: TStrings); overload;
property DefaultInterface: ICorRuntimeHost read FDefaultInterface implements ICorRuntimeHost;
property AppDomains[const Idx: Integer]: TJclClrAppDomain read GetAppDomain; default;
property AppDomainCount: Integer read GetAppDomainCount;
property DefaultAppDomain: IJclClrAppDomain read GetDefaultAppDomain;
property CurrentAppDomain: IJclClrAppDomain read GetCurrentAppDomain;
end;

How to use .Net assembly from Win32 without registration?

Strangely enough, I couldn't find an answer on StackOverflow, and there is not much on the Net, especially for Delphi. I found the solution from examples posted here.
Here's what I got at the end:

function ClrCreateManagedInstance(pTypeName: PWideChar; const riid: TIID;
out ppObject): HRESULT; stdcall; external 'mscoree.dll';

procedure TMyDotNetInterop.InitDotNetAssemblyLibrary;
var
MyIntf: IMyIntf;
hr: HRESULT;
NetClassName: WideString;
begin
//Partial assembly name works but full assembly name is preffered.
NetClassName := 'MyCompany.MyDLLName.MyClassThatImplementsIMyIntf,
MyCompany.MyDLLName';
hr := ClrCreateManagedInstance(PWideChar(NetClassName), IMyIntf, MyIntf);
//Check for error. Possible exception is EOleException with ErrorCode
//FUSION_E_INVALID_NAME = $80131047 2148732999 : The given assembly name
//or codebase was invalid.
//COR_E_TYPELOAD = $80131522 - "Could not find or load a specific type
//(class, enum, etc)"
//E_NOINTERFACE = $80004002 - "Interface not supported".
OleCheck(hr);
end;

BTW, depending on the situation, you might want to load mscoree.dll dynamically, because it might be not present on the system (XP with no .Net Framework)

EDIT: Unfortunately, this was deprecated and stopped working with .Net4 as I just found out. This leaves only two options - CLR hosting and unmanaged export. Also, debugging of .Net4 COM code is broken.

access managed code ( CLR ) DLL with Delphi 7

@AngryHacker, For what you have suggested to be true, the .NET Assembly needs to be marked with the ComVisibleAttribute ( Register for COM Interop option enabled), and expose each function to COM using the [ComVisible(true)].

If you are trying to use a third party assembly (which you did not write) you have to check with the vendor whether that assembly can be used through COM.

Also the assembly does NOT need to be strong named to be accessible via COM.

If you do not want to go the COM way, check out CrossTalk for Delphi :
http://www.atozed.com/CrossTalk/Docs/index.EN.aspx

Returning complex types (Classes, Arrays of Classes) using JCL and CLR

You can't, at least not that way. Delphi and .NET have different object models, and different string types, which aren't compatible with each other. If you want to pass objects between .NET and Delphi modules, the best way is probably to use COM.

How to call .NET from Delphi?

Not terribly familiar with the Saxon API, but I am with Delphi, .NET and COM interoperability.

What I would suggest you do is create a facade pattern around the Saxon API in your favorite (or most tolerable) .NET language. Leave ComVisible True on those wrapper classes. Then access this wrapper assembly via COM Interop in Delphi.

You could really get away with an adapter patter, but since I am assuming you don't need to access the entire Saxon API then a facade is more appropriate.

Why use JCL UNITVERSIONING?

It supports the JclUnitVersioning unit, which exposes the constants like these in a more coherent way:

{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jcl.svn.sourceforge.net/svnroot/jcl/tags/JCL-1.101- Build2725/jcl/source/common/Jcl8087.pas $';
Revision: '$Revision: 1$';
Date: '$Date: 12/05/2008 10:29:10$';
LogPath: 'JCL\source\common'
);
{$ENDIF UNITVERSIONING}

An old version of the JclUnitVersioning unit is here]1 and gives you a rough idea how it works: the unit has a global function GetUnitVersioning: TUnitVersioning; which gives you back the version information for all units that support UNITVERSIONING.

From there you can enumerate them, and ask for details.

This is very handy for instance when you want to know which exact version of a unit gets linked into your .EXE.

--jeroen



Related Topics



Leave a reply



Submit