Search code examples
c++delphipointersdlldllexport

Return double* from c++ dll to delphi program


Im trying to return the array of double (declared as double*) to delphi program. In c++ dll project I have

#define DllExport   __declspec( dllexport )
extern double* array;
extern "C"
{
    DllExport double* SomeMethod(double);
}

and array got deleted when Dll is unloaded

BOOL APIENTRY DllMain( HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
    )
{

switch( ul_reason_for_call ) 
{ 
...

    case DLL_PROCESS_DETACH:
        delete [] array;
        break;
}
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

While I was testing my dll in c++ console application I got the right result after using SomeMethod from dll. Next i tried to test my dll in Delphi but the content of array returned by method is wrong. I used the following code.

TSomeMethod = function(level : Double): PDouble; cdecl;
...
var
    SomeMethod: TSomeMethod;
    arr: PDouble;
...
    if Assigned(SomeMethod) then
        begin
          arr:= SomeMethod(15);
          writeln(arr^:2:0);
          inc(arr);
          writeln(arr^:2:0);
        end
...

What is a proper way to return a double* from c++ dll to use in delphi?

P.S. Other methods work in th right way. For example dll returns char* and in delphi I got it using PAnsiChar

UPDATE

Here is some C++ code from file where SomeMethod is written.

double* array; // yea it's an array that declared as external in other file;
...
double* SomeMethod(double level)
{
    ...
    deque<double> arrayToReturn;
    ... // some actions with deque
    array= new double[arrayToReturn.size()];
    for (unsigned int i = 0; i<arrayToReturn.size(); i++)
        array[i] = arrayToReturn[i];
    return array;
 }

Solution

  • The code in your question works fine. Which means that the problem lies elsewhere. Here's the proof:

    C++

    #include <Windows.h>
    
    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
        )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    
    extern "C" {
    
    __declspec(dllexport) double* SomeMethod(double)
    {
        double* array = new double[2];
        array[0] = 42;
        array[1] = 666;
        return array;
    }
    
    }
    

    Delphi

    {$APPTYPE CONSOLE}
    
    uses
      Windows, SysUtils;
    
    type
      TSomeMethod = function(level : Double): PDouble; cdecl;
    
    var
      SomeMethod: TSomeMethod;
      arr: PDouble;
      lib: HMODULE;
    
    begin
      lib := LoadLibrary('MyDll.dll');
      Win32Check(lib<>0);
      SomeMethod := GetProcAddress(lib, 'SomeMethod');
      Win32Check(Assigned(SomeMethod));
      arr:= SomeMethod(15);
      Writeln(arr^:3:0);
      inc(arr);
      Writeln(arr^:3:0);
      Readln;
    end.
    

    Output

     42
    666