20

誰かが Delphi で CLR をホストする方法の例をここに投稿できますか? ここで同様の質問を読みましたが、Delphi 5 でホストしたいので JCL を使用できません。ありがとうございます。


編集: Fox Pro での CLR のホスティングに関するこの記事は有望に見えますが、Delphi から clrhost.dll にアクセスする方法がわかりません。


編集 2: Delphi 5 の要件をあきらめます。現在、Delphi 7 で JCL を試しています。しかし、やはり例が見つかりません。これが私が今まで持っているものです:

私のC#アセンブリ:

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

にコンパイルしました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;

これはエラーで終了します: EOleError: バリアントはオートメーション オブジェクトを参照していません

私は長い間 Delphi を扱っていないので、ここで立ち往生しています...


解決策: COM の可視性に問題がありましたが、これはデフォルトではありません。これは正しい .NET アセンブリです。

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

重要な注意点:

Delphi から .NET を操作する場合Set8087CW($133F);、プログラムの最初 (つまり の前Application.Initialize;) で呼び出すことが重要です。Delphi はデフォルトで浮動小数点例外を有効にしており(これを参照)、CLR はそれらを好まない。それらを有効にすると、プログラムが奇妙にフリーズしました。

4

5 に答える 5

14

別のオプションがあります。

これがC#コードです。また、管理されていないエクスポートを使用したくない場合でも、IDispatchを経由せずにmscoree(CLRホスティングのもの)を使用する方法を説明します(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();
      }
   }
}

これはDelphiインターフェイス宣言です。

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

管理されていないエクスポートを使用する場合は、次のように実行できます。

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.

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.

この場合、もちろん、C#コードから「UnmanagedExports」クラスを削除できます。

于 2010-01-13T09:09:00.740 に答える
9

クラスはcomvisibleである必要があります。アセンブリ全体にComVisible(false)がある場合は、そうではない可能性があります。

.NetクラスはデフォルトでIDispatchと互換性があるため、クラスが実際にcomvisibleである場合、サンプルは問題なく機能するはずです。

しかし、最初にそれを最小限にまで取り除きます。exeを.Netアセンブリと同じフォルダーに置き、構成ファイルとアプリケーションベースをスキップします。

何かが混乱する前に、例外はここで起こりますよね?

 ov := obj.Unwrap;
于 2010-01-12T20:33:50.743 に答える
7

どうぞ:

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.

注: DelphiNET.NETAdder 型と DelphiNet.dll の 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)))));
于 2010-01-12T20:40:50.117 に答える