【问题标题】:Create C# DLL and Call from Delphi创建 C# DLL 并从 Delphi 调用
【发布时间】:2021-11-17 05:01:03
【问题描述】:

我想使用 Delphi 的第 3 方 dotnet 库(仅几个函数),并计划创建一个 C# DLL 作为接口。我创建了一个简单的演示 DLL 作为 C# (VS 2019/.NET5) 的测试,其中包含一个返回整数的函数(稍后,我想添加一个返回字符串的函数)。从 Delphi 10.4 调用 DLL 时,出现以下错误:

程序入口点Add在动态链接库D:\Source Code\DelphiTestDLLCSharp\Win64\Debug\TestDLLProject.exe中找不到

我正在使用this technique 创建 DLL。

我的 C# 代码在类库中:

using System;
using System.Runtime.InteropServices;

namespace TestDLLForDelphiV2
{
    [ComVisible(true)]
    [Guid("8F8F51AA-1A66-4689-83EF-CF61ED99EA92")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

    public interface ICalc
    {
        int Add();
    }

    [ComVisible(true)]
    [Guid("BEB943AE-A406-4F55-A9E5-DD3B12F8D17B")]
    public class Calc : ICalc
    {
        private int numberOne = 3;
        private int numberTwo = 5;

        // Add two integers
        [ComVisible(true)]
        public int Add()
        {
            return numberOne + numberTwo;
        }         
    }
}

Visual Studio 项目文件:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <Platforms>x64</Platforms>
    <EnableComHosting>true</EnableComHosting>
    <EnableRegFreeCom>true</EnableRegFreeCom>
    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <PlatformTarget>x64</PlatformTarget>
    <EnableComHosting>true</EnableComHosting>
    <EnableRegFreeCom>true</EnableRegFreeCom>
  </PropertyGroup>

</Project>

调用DLL的Delphi代码:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  ShellApi;

function Add: Integer; stdcall; // cdecl;  NOTE - I tried with both stdcall and cdecl
External 'TestDLLForDelphiV2.comhost.dll';  //NOTE - Also attempted with TestDLLForDelphiV2.dll

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  Memo.Clear;

  i := Add;
  Memo.Lines.Add(IntToStr(i));

end;

end.

DLL 是用 .NET5 创建的,据我所知,regasm.exe 不支持它,就像以前的 .NET 版本一样。根据上面的文章,我已经使用 regsvr32.exe 注册了 DLL,并且还尝试了 Reg Free COM 选项(使用项目文件中的 EnableRegFreeCom 标记)。 DLL 和 Delphi 应用程序都编译为 64 位。任何提示、建设性帮助等将不胜感激。

【问题讨论】:

  • 只使用 UnmanagedExports
  • 我不是 Delphi 的大专家,但看起来您不是在尝试通过 COM 调用 DLL,而是作为简单的本机导出函数。尝试使用 CoCreateInstance(我相信 Delphi 对此有自己的 api\wrapper)来访问 COM 对象。
  • 您已将 C# DLL 编写为 COM 库,因此您需要从 Delphi 应用程序通过 COM 访问它。你没有那样做;您正在尝试将其用作标准 DLL 而不是 COM 库。
  • Delphi 有一个功能到import a .NET assembly,并生成一个Delphi 单元与之交互。
  • github.com/3F/DllExport 这就是我所指的

标签: c# delphi dll .net-5 delphi-10.4-sydney


【解决方案1】:

用 c++ 加载 .NET 框架并在那里创建 C# 对象

gcroot<Calc^> calc = nullptr;

bool __stdcall GetCalc(int& obj)
{
  using namespace System::Runtime::InteropServices;
  if (calc.operator->() == nullptr)
    calc= gcnew Calc();
  System::IntPtr p = Marshal::GetIUnknownForObject(calc);

  void* q = p.ToPointer();
  obj= (int)q;
  return true;

}

德尔福:

type
  ICalc=interface(IInterface)
  ['{8F8F51AA-1A66-4689-83EF-CF61ED99EA92}']
    function Add: integer; safecall;
end;

procedure test;
type
  TFunc=function(var ASrv: IInterface): boolean; stdcall;
var
  Lhn    : THandle;
  Lfunc  : TFunc;
  Lif    : IInterface;
  LifCalc: ICalc;
begin
  Lhnd  := LoadLibrary(<C++ DllName>);
  try
    Lfunc := GetProcAdress(Lhnd, 'GetCalc');
    
    Lfunc(Lif);
    if Supports(Lif, ICalc, LifCalc) then
      ShowMessage(LifCalc.Add.ToString)
   else
      raise Exception.Create('Error');
 
 finally
   FreeLibrary(Lhnd);
 end;
end;

C#

namespace TestDLLForDelphiV2
{
[ComVisible(true)]
[Guid("8F8F51AA-1A66-4689-83EF-CF61ED99EA92")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

public interface ICalc
{
    [return: MarshalAs(UnmanagedType.I4)]
    int Add();
}

public class Calc : ICalc
{
    private int numberOne = 3;
    private int numberTwo = 5;

    // Add two integers
    public int Add()
    {
        return numberOne + numberTwo;
    }         
}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多