0

My goal is to call a function written in C++ (with a C interface) from within Delphi (RAD Studio XE6). In the end, the dll will be generated by Visual Studio 2013, but I've tried to start with generating the Dll from RAD Studio XE6.

So, I have created a Dll project in Rad Studio (Using VC++ style Dll). The file is here

#include <vcl.h>
#include <windows.h>

#pragma hdrstop
#pragma argsused

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    return 1;
}

extern "C" int next(int n) {
    return n + 1;
}

It compiles as a Dll. On the Delphi side, the code is as below:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Windows;
function next(a: Int32): Int32; cdecl;
  external 'Project3.dll';
var
  a: Int32;
begin
  try
    a := 3;
    Writeln('Hello world!', next(a));
    sleep(3000);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

The project does compile but does not run. It gives the following error:

*** A stack buffer overrun occurred in "C:\...\Debug\Project1.exe"

It fails on the following assembly line

mov eax,[edi]

I have tried to change cdecl to std call, pascal or register. But nothing works.

Solution: Thanks to Rudy, the following code does work. First the C++ side:

#include <vcl.h>
#include <windows.h>

#pragma hdrstop
#pragma argsused

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    return 1;
}

extern "C" __declspec(dllexport) int __stdcall next(int n) {
    return n + 1;
}

and then the Delphi side.

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Windows;
function next(a: Int32): Int32; stdcall;
  external 'Project3.dll';
var
  a: Int32;
begin
  try
    a := 3;
    Writeln('Hello world!', next(a));
    sleep(3000);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
14
  • That's not really a C++ export, the function is using the C-calling convention. Maybe add extern "C"? C++ is not likely to be supported by Delphi, usually plain C functions are the lowest common denominator that can be imported by any other language.
    – sashoalm
    Commented Nov 10, 2014 at 10:02
  • @sashoalm: Thanks. I have tried that and updated my question. But it does not work either.
    – InsideLoop
    Commented Nov 10, 2014 at 10:09
  • 1
    Are you sure the function is exported? It doesn't look like it. Take a look with a tool like Dependency Walker. If not, read the online help on how to export functions. I guess that a simple directive should be enough, e.g. __declspec(dllexport) or __export or some such. Commented Nov 10, 2014 at 10:24
  • 2
    FWIW, take a look at this article of mine. Commented Nov 10, 2014 at 10:26
  • 1
    @InsideLoop - Also, you should really use Windows API types such as LONG, DWORD, etc., and not C++ types such as int. There is no guarantee that int will be 32 bits, as C++ makes no such guarantees. In addition, the name you exported is mangled -- as the other comment suggested, take a look at your exported function using Dependency Walker. Commented Nov 10, 2014 at 10:26

1 Answer 1

2

You aren't exporting the function. Do that like this:

extern "C" 
{
    __declspec(dllexport) int next(int n)
    {
        return n + 1;
    }
}

Using extern "C", __declspec(dllexport) and the default calling convention of __cdecl will lean to the function being exported undecorated. Any other choice leads to decoration.

On the Delphi side it is:

function next(a: Integer): Integer; cdecl;
  external '...';

Decoration is not such a bad thing but if you want to use stdcall, and avoid decoration, then you should use a .def file to export the function.

11
  • It does not work. I have tried to do it that way, and tdump -ee library.dll tells me that next has been exported but the Delphi application crashes when it runs. But if I compile it with RAD Studio XE6, it works fine. Have you ever managed to mix code coming from Visual Studio 2013 and Delphi XE6?
    – InsideLoop
    Commented Nov 10, 2014 at 16:47
  • It works fine. I don't know what you have got wrong. "Crashes" gives no information. Commented Nov 10, 2014 at 16:50
  • It says: "The application was unable to start correctly (0xc000a200). Click OK to close the application.". And then it breaks at "mov ex,[edi]". So you know, I have created my Dll with Visual Studio 2013 using: New Project->Visual C++->DLL (Windows). Could you please confirm that you have compiled the C++ code with Visual Studio?
    – InsideLoop
    Commented Nov 10, 2014 at 16:54
  • I'm not compiling anything. The error code is STATUS_NOT_APPCONTAINER. Are you building a WinRT DLL? A Windows Store DLL. Commented Nov 10, 2014 at 16:58
  • I have no idea (I am more of a Unix guy). How do we know that? Should I create a WinRT Dll or not? What kind of Dll should I create?. (The Project says: DLL(Windows): A project for a native dynamic-link library (DLL) that can be used by a Windows app or runtime component.)
    – InsideLoop
    Commented Nov 10, 2014 at 17:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.