2010-01-12 5 views
18

누군가 Delphi에서 CLR을 호스팅하는 방법에 대한 예를 게시 할 수 있습니까? 비슷한 question을 여기 읽었지만 JCL을 Delphi 5에서 호스트하고자하므로 사용할 수 없습니다. 감사합니다.JCL이 포함 된/포함되지 않은 델파이에서 CLR 호스팅 - 예 :


편집 : 프로 폭스에서 CLR을 호스팅에 대한이 article 유망 보이지만 내가 델파이에서 clrhost.dll에 액세스하는 방법을 모르겠어요.


편집 2 :는 델파이 5의 요구 사항에 포기. 이제 Delphi 7에서 JCL을 사용하려고합니다.하지만 다시는 예제를 찾을 수 없습니다. 여기에 내가 무엇을 가지고 지금까지 :

내 C# 어셈블리 : 나는 DelphiNET.dll로 컴파일

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

.

는 지금은 델파이에서이 어셈블리를 사용하려면 :

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가 : 변형이

내가 긴 델파이와 함께 일하지 않은 자동화 객체를 참조하지 않습니다 T : 시간 그래서


솔루션 ... 여기 붙어 여기에 기본적으로없는 COM 가시성의 문제가있었습니다. (즉 Application.Initialize; 전)

델파이 .NET 작업, 그것은 프로그램의 시작 부분에 Set8087CW($133F);를 호출하는 것이 중요하다 :

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

중요 사항 :이 올바른 .NET 어셈블리입니다. Delphi는 기본적으로 부동 소수점 예외를 활성화했으며 (this 참조) CLR은 부동 소수점 예외를 선호하지 않습니다. 내가 사용할 수있을 때, 내 프로그램이 이상하게 얼어 버렸다.

+2

왜 Delphi 5에서 JCL을 사용할 수 없습니까? 사소한 변화가 있은 후에도? –

+0

JclDotNet.pas는 Delphi 6에서 개발되었으며 Delphi 5에서 사소한 변경 사항을 사용하지 않았습니다. –

+0

Managed VCL을 고려해 보셨습니까? –

답변

8

클래스는 이해할 수 있어야합니다. 전체 어셈블리에 대해 ComVisible (false)을 사용하면 그렇지 않을 수 있습니다. 샘플 클래스는 정말 대해 ComVisible 경우 ..

를 잘 작동하지만 먼저 최소한에 아래로 제거해야하므로

닷넷 클래스는 기본적으로 IDispatch를 호환됩니다. exe를 .Net 어셈블리와 동일한 폴더에두고 구성 파일과 응용 프로그램베이스를 건너 뜁니다.

뭔가가 섞이기 전에 예외는 여기에서 발생합니다. 맞습니까? 여기

ov := obj.Unwrap; 
+0

+1 .Net 메소드를 호출하기 위해 COM을 사용하라는 제안에 대해서는 +1하지만 실제로 그가 요구 한 것은 아닙니다. 그는 어셈블리를 변경할 수 없을 수도 있습니다. 내 답변에 나와 있듯이 COM이 없어도 COM을 볼 수있게 만들지 않아도됩니다. –

+1

COM을 사용하지 않고 클래스를 ComVisible로 표시합니다. 샘플은 CLR의 COM/Interop 인프라에 의존하여 IDispatch로 마샬링 된 .Net 인스턴스를 가져옵니다. 이것은 클래스가 ComVisible 인 경우에만 작동합니다 (기본값이지만 어셈블리에 대해 비활성화되어있을 수 있음) –

+0

수정되었습니다. 나는 그것이 그것이 사실로 사실 일 것이라고 기대하지 않았다. 형식이 COM 표시되지 않으면 내 예제는 실제로 실패합니다. 이것은 IMHO의 사용을 상당히 제한합니다. –

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. 

참고 :는 가정 그 DelphiNET.NETAdder 유형과 DelphiNet의 ADD3 방법.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))))); 
+1

IDispatch 나 IUnknown을 필요로하지 않으므로 COM/Interop이 필요 없기 때문에 작동합니다. 당신이 볼 수없는 수업을 다루어야하는 경우에 대한 훌륭한 예입니다. 따라서 : +1 –

+0

+1 업데이트 된 예 (ComVisible 제외)는 훌륭합니다! 실행하려면 다음이 필요합니다. ActiveX 사용; var Assm : _Assembly; var T : _Type; var Params : Variant; –

+0

하지만 훨씬 느려질 수 밖에 없습니다. 3 분 안에 회의에 있어야 해. 전,하지만 나중에 다른 샘플 (IDispatch 없음)을 알려 드리겠습니다. –

12

다른 옵션이 있습니다.

그건 C# 코드입니다. 그리고 심지어 my unmanaged exports을 사용하고 싶지 않더라도 IDispatch (IDispatch는 꽤 느림)를 거치지 않고 mscoree (CLR 호스팅 항목)를 사용하는 방법을 설명하면 여전히 이됩니다.

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(); 
     } 
    } 
} 

이 델파이 인터페이스 선언입니다 : 당신이 관리되지 않는 수출을 사용하는 경우

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. 

을 나는 라스 '샘플을 적용 할 때, 그것은 것 모양은 다음과 같습니다.

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"클래스를 제거 할 수 있습니다.

관련 문제