使用/不使用JCL在Delphi中托管CLR - 示例

Luk*_*sky 18 .net c# delphi clr host

有人可以在这里发布一个如何在Delphi中托管CLR的例子吗?我在这里读过类似的问题,但我不能使用JCL,因为我想在Delphi 5中托管它.谢谢.


编辑:文章关于福克斯临托管CLR看起来很有希望,但我不知道如何从德尔福访问clrhost.dll.


编辑2:我放弃了Delphi 5的要求.现在我正在尝试使用Delphi 7进行JCL.但是我再也找不到任何示例.这就是我现在所拥有的:

我的C#程序集:

namespace DelphiNET
{
    public class NETAdder
    {
        public int Add3(int left)
        {
            return left + 3;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我把它编译成了DelphiNET.dll.

现在我想使用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;
Run Code Online (Sandbox Code Playgroud)

这以错误结束:EOleError:Variant不引用自动化对象

我已经很久没和德尔福合作了,所以我被困在这里......


解决方案: COM可见性存在问题,默认情况下不存在.这是正确的.NET程序集:

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

重要的提示:

使用Delphi中的.NET时,重要Set8087CW($133F);的是在程序开始时(即之前Application.Initialize;)调用.Delphi默认启用浮点异常(请参阅此内容),CLR不喜欢它们.当我启用它们时,我的程序奇怪地冻结了.

Rob*_*cke 12

这是另一种选择.

这是C#代码.即使你不想使用我的非托管导出,它仍然会解释如何使用mscoree(CLR托管的东西)而不通过IDispatch(IDispatch非常慢).

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();
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

这是Delphi接口声明:

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

如果使用非托管导出,则可以这样做:

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.
Run Code Online (Sandbox Code Playgroud)

当我调整Lars的样本时,它看起来像这样:

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.
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您可以从C#代码中删除"UnmanagedExports"类,当然.


Rob*_*cke 8

这堂课必须是可见的.如果您对整个程序集具有ComVisible(false),则可能不是这种情况.

默认情况下.Net类将与IDispatch兼容,因此如果类真的是可见的,那么你的样本应该可以正常工作.

但首先将它剥离到最低限度.将您的exe放在与.Net程序集相同的文件夹中,并跳过配置文件和应用程序库.

在事情变得混乱之前,这里发生了异常,对吧?

 ov := obj.Unwrap;
Run Code Online (Sandbox Code Playgroud)


Lar*_*ens 6

干得好:

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.
Run Code Online (Sandbox Code Playgroud)

注意:假设DelphiNET.NET中的DelphiNET.NETAdder类型和Add3方法是ComVisible.感谢罗伯特.

更新:

使用反射时,您不需要ComVisible属性.下一个例子即使不是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)))));
Run Code Online (Sandbox Code Playgroud)