代码之家  ›  专栏  ›  技术社区  ›  jonimv

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

  •  1
  • jonimv  · 技术社区  · 7 年前

    我使用Delphi 2005(是的,这是一个非常旧的版本,但目前我必须使用它),并且我尝试使用Visual Studio 2017使用C#创建的DLL来查看是否可以使其正常工作。其想法是,由于C#比这个旧的Delphi先进得多,我可以调用DLL中的一些方法,而不是用Delphi编程(其中一些方法已经由我们公司的其他人编程)。我的问题是,我不太确定如何做到这一点。

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

    首先,我想知道我是否正确创建了PoC DLL。我做了一个新项目(类库),并为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文件的目录相同的dll。我试图将“函数和(…”开头的一行放在但这显然不是一件正确的事情。我还试图保持代码的原样,只在私有声明下添加函数声明,但两者都不起作用。

    欢迎任何帮助。

    1 回复  |  直到 7 年前
        1
  •  5
  •   David Heffernan    7 年前

    错误代码是 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;
    }