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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
jonimv
  • 31
  • 1
  • 6
  • Possible duplicate of [How to Create DLL in C# and call in Delphi XE6](https://stackoverflow.com/questions/27968022/how-to-create-dll-in-c-sharp-and-call-in-delphi-xe6) – Anton Semenov Feb 28 '18 at 11:01
  • @AntonSemenov That's not a duplicate of this question. This one is about a specific error. Although I am sure that there are duplicates in existence. – David Heffernan Feb 28 '18 at 11:10
  • Please stop asking new questions by edits to this one. Please read the articles at the [help] if you are not sure how this site works. – David Heffernan Feb 28 '18 at 11:12

1 Answers1

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;
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks for the suggestions. I updated my Delphi code as you suggested (I edited my original post to reflect it). I also checked the bitness and that was wrong, the DLL was for some reason 64bit but I managed to make it 32bit. Still, the same problem. – jonimv Feb 28 '18 at 11:05
  • No. You won't have that problem if both modules are 32 bit. I guess you are finding the previous 64 bit version of the DLL still. And I rolled back your question edit which invalidated part of my answer. We aren't in the business of trying to hit a moving target here. I'm not going to edit my answer time and again to match your edits that change the question. – David Heffernan Feb 28 '18 at 11:08
  • 4
    Looking at the latest edit that I rolled back, you actually now have a completely different error condition. So when you said "same problem", that's contradicted by what you posted. You now manage to start executing the application. Which means that the question you asked has been answered, and that you now have a new problem. Questions here are not for extended debugging sessions where you get to have us debug your entire program, from one bug to the next until they are all gone. You ask a single question, and it gets an answer. That's it. – David Heffernan Feb 28 '18 at 11:19
  • And as for that error, again it is an `NTSTATUS` code. `0xc0000409` is `STATUS_STACK_BUFFER_OVERRUN`. They are listed here: https://msdn.microsoft.com/en-gb/library/cc704588.aspx I expect that problem is because you didn't make the C# method static. I'm afraid I didn't spot that error originally, but the answer now describes it. So, there were three problems. You asked about the bad image format exception and sorting the bitness fixes that, and at that point, formally, the question is answered. But you've actually got the answers to the subsequent issues as well. – David Heffernan Feb 28 '18 at 11:40