Подтвердить что ты не робот

Хостинг CLR в Delphi с/без JCL - пример

Может кто-нибудь, пожалуйста, напишите здесь пример того, как размещать CLR в Delphi? Я прочитал аналогичный question здесь, но я не могу использовать JCL, поскольку хочу разместить его в Delphi 5. Спасибо.


EDIT: Эта статья о размещении CLR в Fox Pro выглядит многообещающе, но я не знаю, как Доступ к clrhost.dll из Delphi.


Изменить 2: Я отказываюсь от требования Delphi 5. Теперь я пытаюсь использовать JCL с Delphi 7. Но опять же я не могу найти ни одного примера. Вот что я имею до сих пор:

Моя сборка С#:

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: Variant не ссылается на объект автоматизации

Я не работал с Delphi в течение долгого времени, поэтому я застрял здесь...


Решение: В просмотре COM была проблема, которая по умолчанию отсутствует. Это правильная сборка .NET:

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

Важное примечание:

При работе с .NET из Delphi важно вызвать Set8087CW($133F); в начале вашей программы (т.е. до Application.Initialize;). По умолчанию Delphi разрешает исключения с плавающей запятой (см. this), и CLR им не нравится. Когда я включил их, моя программа была заморожена.

4b9b3361

Ответ 1

Класс должен быть понятным. Что может быть не так, если у вас есть ComVisible (false) для всей сборки.

.Net-классы по умолчанию будут совместимы с IDispatch, поэтому ваш образец должен работать нормально, если класс действительно доступен..

Но сначала разделите его на минимальный минимум. Поместите ваш exe в ту же папку, что и ваша сборка .Net, и пропустите файл конфигурации и базу приложений.

Прежде чем что-то перепутается, исключение происходит здесь, верно?

 ov := obj.Unwrap;

Ответ 2

Вот еще один вариант.

Это код С#. И даже если вы не хотите использовать мой неуправляемый экспорт, он все равно будет объясните, как использовать 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();
      }
   }
}

Это объявление интерфейса 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.

В этом случае, конечно, вы можете удалить класс "UnmanagedExports" из кода С#.

Ответ 3

Здесь вы идете:

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 и метод Add3 в DelphiNet.dll ComVisible. Благодаря Robert.

Обновление

При использовании отражения вам не нужен атрибут 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)))));