How to use a DLL created with C# in Delphi

1

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. 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). 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. 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.

First I would like to know if I have created the PoC DLL correctly. 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.

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. 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). 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. 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.

Any help is welcome.

c#
delphi
dllimport
asked on Stack Overflow Feb 28, 2018 by jonimv • edited Feb 28, 2018 by David Heffernan

1 Answer

5

The error code is the NTSTATUS code STATUS_INVALID_IMAGE_FORMAT. That is typically a 64 bit process trying (and failing) to load a 32 bit DLL, or vice versa. 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.

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. Change the Delphi to:

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. I'd prefer to be explicit:

[DllExport(CallingConvention = CallingConvention.StdCall)]

And the final problem is that your C# method must be declared static.

[DllExport(CallingConvention = CallingConvention.StdCall)]
public static int sum(int a, int b)
{
    return a + b;
}
answered on Stack Overflow Feb 28, 2018 by David Heffernan • edited Feb 28, 2018 by David Heffernan

User contributions licensed under CC BY-SA 3.0