在Delphi中使用/不使用JCL托pipeCLR – 例子

有人可以请在这里举一个例子如何在Delphi中托pipeCLR? 我在这里读过类似的问题 ,但我不能使用JCL,因为我想在Delphi 5中托pipe它。谢谢。


编辑:这篇文章关于托pipe在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:Variant不引用自动化对象

我有很长一段时间没有与delphi合作,所以我被困在这里…


解决scheme: COM默认情况下不存在问题。 这是正确的.NET程序集:

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

重要的提示:

在使用Delphi的.NET时,调用Set8087CW($133F);很重要Set8087CW($133F); 在你的程序的开始(即在Application.Initialize;之前)。 Delphi默认情况下启用了浮点exception(请参阅本文 ),而CLR不喜欢它们。 当我启用它们时,我的程序奇怪地冻结了。

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

.Net类默认是IDispatch兼容的,所以你的示例应该工作得很好,如果这个类真的是可见的。

但是首先将它剥离到最低限度。 把你的exe文件放在你的.Net程序集所在的文件夹中,然后跳过configuration文件和应用程序库。

在事情混淆之前,这里发生了exception,对不对?

  ov := obj.Unwrap; 

这是另一种select。

这是C#代码。 即使你不想使用我的非托pipe导出 ,它仍然会解释如何使用mscoree(CLR托pipe的东西),而不通过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; 

如果你使用非托pipe导出,你可以这样做:

 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”类。

干得好:

 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.dll中的DelphiNET.NETAdAddertypes和Add3方法是ComVisible 。 感谢罗伯特 。

更新

使用reflection时,您不需要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)))));