简体   繁体   English

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

[英]How to use a DLL created with C# in Delphi

I use Delphi 2005 (yes, it's pretty old version but at the moment I that's what I have to use) and I have tried to use a DLL created with C# using Visual Studio 2017 to see if I can make it work. 我使用的是Delphi 2005(是的,它是相当旧的版本,但目前我必须使用它),并且我尝试使用通过Visual Studio 2017 C#创建的DLL,以查看是否可以使它工作。 The idea is that as C# is much more advanced than this old Delphi I could call some methods in the DLL instead of programming those with Delphi (some of those methods are already programmed by some other people in our company). 想法是,由于C#比这个旧的Delphi先进得多,因此我可以在DLL中调用某些方法,而不是使用Delphi进行编程(这些方法中的某些已经由我们公司的其他人员进行了编程)。 My problem is that I am not quite sure how to do this. 我的问题是我不太确定如何执行此操作。

I have understood that it is possible to call a DLL from Delphi without registering the DLL. 我了解可以从Delphi调用DLL而无需注册DLL。 This is actually more or less gamebreaker if there is no actual way to use a DLL without registering it because it makes delivering our software a bit more complicated that how it works now. 如果没有未经注册就没有使用DLL的实际方法,这实际上或多或少地是破坏者,因为与我们现在的工作方式相比,它使交付我们的软件更加复杂。

First I would like to know if I have created the PoC DLL correctly. 首先,我想知道是否正确创建了PoC DLL。 I made a new project (Class Library) and compiled it for x86 since the programs created with Delphi 2005 are 32-bit programs and here's the code for this very simple 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;
        }
    }
}

Is this code correct? 此代码正确吗?

Another thing is that I am not entirely certain that I have created the Delphi project correctly. 另一件事是,我不能完全确定自己已正确创建了Delphi项目。 I can build it without errors but when I try to run it I get an error message: 我可以构建它而没有错误,但是当我尝试运行它时,我收到一条错误消息:

The application was unable to start correctly (0xc000007b). 应用程序无法正确启动(0xc000007b)。 Click OK to close the application. 单击“确定”关闭该应用程序。

Here's the code. 这是代码。

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.

I have the CalcTest.dll in the same directory as where Delphi creates the exe file. 我在与Delphi创建exe文件所在的目录中有CalcTest.dll。 I tried to place the line starting "function sum(..." under private declaration but that was clearly not a right thing to do. I have also tried to leave the code as is and just add function declaration under private declaration but neither worked. 我试图将以“ function sum(...”开头的行放置在私有声明下,但这显然不是正确的事情。我也试图将代码保持原样,仅在私有声明下添加函数声明,但均无济于事。

Any help is welcome. 欢迎任何帮助。

The error code is the NTSTATUS code STATUS_INVALID_IMAGE_FORMAT . 错误代码是NTSTATUS代码STATUS_INVALID_IMAGE_FORMAT That is typically a 64 bit process trying (and failing) to load a 32 bit DLL, or vice versa. 通常,这是一个试图加载32位DLL(并且失败)的64位进程,反之亦然。 You need to make sure that the bitness of all modules matches. 您需要确保所有模块的位匹配。 Since your Delphi compiler can only produce 32 bit executables, your C# project must target x86. 由于您的Delphi编译器只能生成32位可执行文件,因此您的C#项目必须以x86为目标。

The next problem is one of calling conventions. 下一个问题是调用约定之一。 Your C# export uses stdcall , but your Delphi import does not specify a calling convention and so you defaults to register . 您的C#导出使用stdcall ,但是您的Delphi导入未指定调用约定,因此默认为register Change the Delphi to: 将Delphi更改为:

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

Because it is so important to match the binary interfaces when writing interop code, my inclination would be not to rely on the default calling convention of the DllExport attribute. 因为在编写互操作代码时匹配二进制接口非常重要,所以我倾向于不要依赖DllExport属性的默认调用约定。 I'd prefer to be explicit: 我宁愿明确:

[DllExport(CallingConvention = CallingConvention.StdCall)]

And the final problem is that your C# method must be declared static . 最后一个问题是您的C#方法必须声明为static

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM