Igor Simoes
Igor Simoes

Reputation: 31

DLL function that exports a pointer do Delphi program

I have a simple program that exports a DLL, this DLL exports functions from another DLL:

// SDK_DLL.cpp : 

#include "functions.h"
#include "functions_advanced.h" 
#include "stdafx.h"
#include <stdio.h>
using namespace std;

extern "C"
{
    __declspec(dllexport) void DisplayHelloFromDLL()
    {
        printf("Hello from DLL...");
    }

    __declspec(dllexport) function_config FuncInit = appd_config_init();

    __declspec(dllexport) function_config * FuncInit2()
    {
        function_config* cfg = function_config_init();
        return cfg;
    }
}

The function_config_init() returns a pointer, I cannot seem to find a way of making this proper export declaration.

I am loading a simple function to Delphi this way:

procedure DisplayHelloFromDLL; external 'C:\Users\Administrator\Documents\Visual Studio 2017\Projects\SDK_DLL\Debug\SDK_DLL.dll';

Will I need to change the way I am loading this pointer returning function?

Thanks a lot for your help.

Upvotes: 0

Views: 224

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598011

FuncInit is an exported variable. Delphi does not support importing of variables via external, only of functions. If you need to import FuncInit, you will have to use GetProcAddress() directly to get a pointer to the variable at runtime:

type
  // you did not show the C/C++ declaration
  // of function_config, so I can't provide
  // a translation here, but it is likely to
  // be a struct, which is a record in Delphi ...
  function_config = ...;
  pfunction_config = ^function_config;

function GetFuncInit: pfunction_config;
begin
  Result := pfunction_config(GetProcAddress(GetModuleHandle('SDK_DLL.dll'), 'FuncInit'));
end;

var
  FuncInit: pfunction_config;

FuncInit := GetFuncInit;

For purposes of interop across languages/compilers, the only portable calling conventions are cdecl and stdcall. When no calling convention is specified in code, the default used by most C and C++ compilers is __cdecl (but can usually be specified in compiler settings), while the default used by Delphi is register instead (__fastcall in C++Builder).

When no parameters or return value are used, like in DisplayHelloFromDLL(), then declaring the wrong calling convention does not really matter. But when parameters and/or a return value are used, like in FuncInit2(), then declaring the correct calling convention matters. See Pitfalls of converting for more details.

So, the two DLL functions in question would likely need to be declared like the following in Delphi:

type
  function_config = ...;
  pfunction_config = ^function_config;

procedure DisplayHelloFromDLL; cdecl; external 'SDK_DLL.dll' name '_DisplayHelloFromDLL';
function FuncInit2: pfunction_config; cdecl; external 'SDK_DLL.dll' name '_FuncInit2';

If the DLL uses a .def file to remove name mangling from the exported names, you can omit the name attribute:

type
  function_config = ...;
  pfunction_config = ^function_config;

procedure DisplayHelloFromDLL; cdecl; external 'SDK_DLL.dll';
function FuncInit2: pfunction_config; cdecl; external 'SDK_DLL.dll';

Upvotes: 2

Related Questions