c# .net delphi clr host

c# - Hosting CLR en Delphi con/sin JCL-ejemplo



.net (3)

¿Alguien puede publicar aquí un ejemplo de cómo alojar CLR en Delphi? He leído una pregunta similar aquí, pero no puedo usar JCL porque quiero alojarlo en Delphi 5. Gracias.

EDITAR: Este artículo sobre el alojamiento de CLR en Fox Pro parece prometedor, pero no sé cómo acceder clrhost.dll desde Delphi.

Editar 2: renuncio al requisito de Delphi 5. Ahora estoy probando JCL con Delphi 7. Pero nuevamente no puedo encontrar ningún ejemplo. Esto es lo que tengo hasta ahora:

Mi ensamblaje de C #:

namespace DelphiNET { public class NETAdder { public int Add3(int left) { return left + 3; } } }

Lo he compilado en DelphiNET.dll .

Ahora quiero usar este ensamblaje de Delphi:

uses JclDotNet, mscorlib_TLB; procedure TForm1.Button1Click(Sender: TObject); var clr: TJclClrHost; ads: TJclClrAppDomainSetup; ad: TJclClrAppDomain; ass: TJclClrAssembly; obj: _ObjectHandle; ov: OleVariant; begin clr := TJclClrHost.Create(); clr.Start; ads := clr.CreateDomainSetup; ads.ApplicationBase := ''C:/Delhi.NET''; ads.ConfigurationFile := ''C:/Delhi.NET/my.config''; ad := clr.CreateAppDomain(''myNET'', ads); obj := (ad as _AppDomain).CreateInstanceFrom(''DelphiNET.dll'', ''DelphiNET.NETAdder''); ov := obj.Unwrap; Button1.Caption := ''done '' + string(ov.Add3(5)); end;

Esto finaliza con un error: EOleError: Variant no hace referencia a un objeto de automatización

No he trabajado con Delphi durante mucho tiempo, así que estoy atrapado aquí ...

Solución: Hubo un problema en la visibilidad COM que no es por defecto. Este es el ensamblaje correcto de .NET:

namespace DelphiNET { [ComVisible(true)] public class NETAdder { public int Add3(int left) { return left + 3; } } }

Nota IMPORTANTE:

Cuando se trabaja con .NET desde Delphi, es importante llamar a Set8087CW($133F); al comienzo de su programa (es decir, antes de la Application.Initialize; ). Delphi ha habilitado excepciones de coma flotante por defecto (ver esto ) y al CLR no le gustan. Cuando los tuve habilitados, mi programa se bloqueó extrañamente.


La clase tiene que ser comisionable. Lo cual podría no ser el caso si tiene ComVisible (falso) para toda la asamblea.

Las clases .Net serán compatibles con IDispatch por defecto, por lo que su muestra debería funcionar bien, si la clase es realmente comisible.

Pero primero quítelo al mínimo. Coloque su archivo exe en la misma carpeta que su ensamblado .Net y omita el archivo de configuración y la base de la aplicación.

Antes de que algo se mezcle, la excepción sucede aquí, ¿verdad?

ov := obj.Unwrap;


Aquí hay otra opción.

Ese es el C # Code. E incluso si no desea utilizar mis exportaciones no administradas , aún así explique cómo usar mscoree (el material de alojamiento de CLR) sin pasar por IDispatch (IDispatch es bastante lento).

using System; using System.Collections.Generic; using System.Text; using RGiesecke.DllExport; using System.Runtime.InteropServices; namespace DelphiNET { [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("ACEEED92-1A35-43fd-8FD8-9BA0F2D7AC31")] public interface IDotNetAdder { int Add3(int left); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] public class DotNetAdder : DelphiNET.IDotNetAdder { public int Add3(int left) { return left + 3; } } internal static class UnmanagedExports { [DllExport("createdotnetadder", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)] static void CreateDotNetAdderInstance([MarshalAs(UnmanagedType.Interface)]out IDotNetAdder instance) { instance = new DotNetAdder(); } } }

Esta es la declaración de interfaz de Delphi:

type IDotNetAdder = interface [''{ACEEED92-1A35-43fd-8FD8-9BA0F2D7AC31}''] function Add3(left : Integer) : Integer; safecall; end;

Si usa exportaciones no gestionadas, puede hacerlo así:

procedure CreateDotNetAdder(out instance : IDotNetAdder); stdcall; external ''DelphiNET'' name ''createdotnetadder''; var adder : IDotNetAdder; begin try CreateDotNetAdder(adder); Writeln(''4 + 3 = '', adder.Add3(4)); except on E: Exception do Writeln(E.ClassName, '': '', E.Message); end; end.

Cuando adapte la muestra de Lars, se vería así:

var Host: TJclClrHost; Obj: IDotNetAdder; begin try Host := TJclClrHost.Create; Host.Start(); WriteLn(''CLRVersion = '' + Host.CorVersion); Obj := Host.DefaultAppDomain .CreateInstance(''DelphiNET'', ''DelphiNET.DotNetAdder'') .UnWrap() as IDotNetAdder; WriteLn(''2 + 3 = '', Obj.Add3(2)); Host.Stop(); except on E: Exception do Writeln(E.Classname, '': '', E.Message); end; end.

En este caso, puedes eliminar la clase "UnmanagedExports" del código C #, por supuesto.


Aqui tienes:

program CallDotNetFromDelphiWin32; {$APPTYPE CONSOLE} uses Variants, JclDotNet, mscorlib_TLB, SysUtils; var Host: TJclClrHost; Obj: OleVariant; begin try Host := TJclClrHost.Create; Host.Start; WriteLn(''CLRVersion = '' + Host.CorVersion); Obj := Host.DefaultAppDomain.CreateInstance(''DelphiNET'', ''DelphiNET.NETAdder'').UnWrap; WriteLn(''2 + 3 = '' + IntToStr(Obj.Add3(2))); Host.Stop; except on E: Exception do Writeln(E.Classname, '': '', E.Message); end; end.

Nota: Supone que el tipo DelphiNET.NETAdder y el método Add3 en DelphiNet.dll es ComVisible . Gracias a Robert .

Actualización :

Cuando usa la reflexión, no necesita el atributo ComVisible. El siguiente ejemplo incluso funciona sin ser ComVisible.

Assm := Host.DefaultAppDomain.Load_2(''NetAddr''); T := Assm.GetType_2(''DelphiNET.NETAdder''); Obj := T.InvokeMember_3(''ctor'', BindingFlags_CreateInstance, nil, null, nil); Params := VarArrayOf([2]); WriteLn(''2 + 3 = '' + IntToStr(T.InvokeMember_3(''Add3'', BindingFlags_InvokeMethod, nil, Obj, PSafeArray(VarArrayAsPSafeArray(Params)))));