如何在 Delphi 中使用用 C# 创建的 DLL

How to use a DLL created with C# in Delphi

我使用 Delphi 2005(是的,它是相当旧的版本,但目前我必须使用它)并且我尝试使用使用 Visual Studio 2017 通过 C# 创建的 DLL看看我能否让它发挥作用。这个想法是,由于 C# 比这个旧的 Delphi 先进得多,我可以在 DLL 中调用一些方法,而不是用 Delphi 编程那些方法(其中一些方法已经被我们的其他人编程了)公司)。我的问题是我不太确定该怎么做。

我了解到可以从 Delphi 调用 DLL 而无需注册 DLL。如果没有实际的方法在不注册的情况下使用 DLL,这实际上或多或少是游戏破坏者,因为它使我们的软件交付比现在的工作方式更加复杂。

首先我想知道我是否正确创建了PoC DLL。我创建了一个新项目(Class 库)并将其编译为 x86,因为使用 Delphi 2005 创建的程序是 32 位程序,这里是这个非常简单的 DLL 的代码。

using RGiesecke.DllExport;
using System;

namespace CalcTest
{
    public class CalcTest
    {
        [DllExport]
        public int sum(int a, int b)
        {
            return a + b;
        }
    }
}

此代码正确吗?

另一件事是我不能完全确定我是否正确创建了 Delphi 项目。我可以毫无错误地构建它,但是当我尝试 运行 它时,我收到一条错误消息:

应用程序无法正确启动 (0xc000007b)。单击“确定”关闭应用程序。

这是代码。

unit TestForm_u;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TTestForm = class(TForm)
    Button1: TButton;
    summa_lb: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure Laske;
  public
    { Public declarations }
  end;

var
  TestForm: TTestForm;

implementation

{$R *.dfm}

function sum(a, b: integer): integer; external 'CalcTest.dll';

procedure TTestForm.Button1Click(Sender: TObject);
begin
  Laske;
end;

procedure TTestForm.Laske;
var
  x,y,z: integer;
begin
  x := 1;
  y := 2;
  //z := x + y;
  z := sum(x, y);

  summa_lb.Caption := IntToStr(z);
end;

end.

我在 Delphi 创建 exe 文件的同一目录中有 CalcTest.dll。我试图将 "function sum(..." 开头的行放在私有声明下,但这显然不是正确的做法。我也尝试过保持代码不变,只是在私有声明下添加函数声明,但都没有用。

欢迎任何帮助。

错误代码是 NTSTATUS 代码 STATUS_INVALID_IMAGE_FORMAT。这通常是 64 位进程尝试(但失败)加载 32 位 DLL,反之亦然。您需要确保所有模块的位数都匹配。由于您的 Delphi 编译器只能生成 32 位可执行文件,因此您的 C# 项目必须以 x86 为目标。

下一个问题是调用约定。您的 C# 导出使用 stdcall,但您的 Delphi 导入未指定调用约定,因此您默认为 register。将 Delphi 更改为:

function sum(a, b: integer): integer; stdcall; external 'CalcTest.dll';

因为在编写互操作代码时匹配二进制接口非常重要,所以我倾向于不依赖 DllExport 属性的默认调用约定。我更愿意直截了当:

[DllExport(CallingConvention = CallingConvention.StdCall)]

最后一个问题是您的 C# 方法必须声明 static

[DllExport(CallingConvention = CallingConvention.StdCall)]
public static int sum(int a, int b)
{
    return a + b;
}