How to call some C++ functions from Delphi

I'm going to write a little piece of code to connect to a DLL written in C++ by other developer.
I don't know the inside of the C++ code, but I was told how the functions look in C++.
I was also told that I "have to copy" the data as soon as they function returns.
I'm not in a position to ask more to the other developer.

These are some examples. I got these from the "h" file.

#define SomeAPI extern "C" __declspec(dllexport)
typedef void* someHandle;

Open in new window


Case 1:
SomeAPI int api_GetHandle(someHandle* hdlReturn);

Open in new window

I understand if the handle is already a pointer and it's again in the function, is it a PPointer?
In this function the "int" return type is just a 0 or 1 value in case of error. The good one is "someHandle".
I know the Handle will be an integer number for me, I don't understand why they have it so "generic".
Why it's not marked as "out" parameter in C++?

Case 2:

SomeAPI int api_KillHandle(someHandle hdl);

Open in new window

In this case, he doesn't have someHandle as a Pointer, however, the handle is already a Pointer type.
How do I call this one?

Case 3

This is to return an string from the DLL:

   SomeAPI int api_GetSomeString(someHandle hdl, int index, char** strRet);

Open in new window

I will send the magic handle, plus another number, then I'll get a string back.
Again my doubt about not having some kind of "out" specification.
And also, how do I know the length of the string? Should be safe to just cast it this way PChar(strRet)^?
How do I call this one?

My main doubt is if I have to declare and "New" these pointers and ppointers, and then "Dispose" them in Delphi, or should I not.

Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Ephraim WangoyaCommented:

There are no out parameters in C, just pointers

  PPChar = ^PChar;

function api_GetHandle(hdlReturn: PHandle): Integer; cdecl;

function api_KillHandle(hdl: PHandle): Integer; cdecl;

function api_GetSomeString(hdl: PHandle; index: Integer; strRet: PPChar): Integer; cdecl;

//for this, looks like Index will contain the length of the string but it should have been a pointer, In that case I suspect
//the dll will allocate memory for this string therefore you will be responsible for destroying it, but this is just a guess,
//you need the API documentation to call it you may use

  H: THandle;
  I: Integer;
  P: PChar;

Result := api_GetSomeString(@H, I, @P)

Dagan HooverDeveloperCommented:
Or you could just use "var" parameters...
I am guessing the strings are null-terminated which is common way to do it in C.
I wrote up some sample code how I think it should be declared and used.
type PPChar = ^PChar;
     PPointer = ^Pointer; 
function api_GetHandle(hdlReturn: PPointer): integer; external 'whatever.dll';
function api_KillHandle(handle: Pointer): integer; external 'whatever.dll';
function api_GetSomeString(hdl: Pointer; index: integer; strRet: PPChar): integer; 


procedure testproc;
var handle: Pointer;
      gotstring: String;
      strresult: PChar;
if api_GetHandle(@handle)=0 then
   {do something with handle}
   if api_GetSomeString(handle,4,@strresult)=0 then
      strresult := StrPas(strresult);
   if api_KillHandle(handle)=1 then

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

fischermxAuthor Commented:

In your code your declaring "handle" as just a Pointer, while in my case the C++ declaration is a PPointer.
Not sure is that's intended.
Ephraim WangoyaCommented:

You dont have to declare it as a Pointer to a Pointer
You can simply pass the address of the Pointer

See how I use @ in my function calls
Only one of the functions you showed had the pointer pointer; I used PPointer for that one.  But it would be clearer to follow ewangoya's example and type it as THandle and PHandle instead of just Pointer.
fischermxAuthor Commented:
Okey, thanks I will use the @.

I have a side issue right now.

I don't have the C++ dll yet, so, for testings, I made a DLL myself in Delphi and I can't get the proper pointer from the DLL.
Unless I use "var" in the parameter in the function signature then works.
But I've never seen a dll interface declaring "var" parameters :(

I mean, I'm trying to make the function that will use be called this way api_GetHandle(hdlReturn: PPointer): integer
and have an integer returned in the handle pointer, but doesn't work, only if I use "var" in the parameter.

fischermxAuthor Commented:
Actually, in my own fake function, whatever I assign to "hdlReturn", I get a compiler warning that the value is never used.
Seems, Delphi is discarding the variable.
If you're treating handles as integers then declare it PInt instead of PPointer, or maybe declare it PHandle but define "type PHandle = ^Int;".

I don't know whether using "var handle: integer" works the same as "handle: PInt" but it's worth a try.  In theory it does the same thing or almost the same thing.  (Although from your last message, it sounds like it doesn't work; might just not be allowed with cdecl/external declaration.

fischermxAuthor Commented:
In my fake function, my assignments to the handle were being warned by the compiler.
I knew the value was going to be discarded.

  PSomeHandle = PPointer;
  SomeHandle = Pointer;

  fHandle : SomeHandle;

function api_GetHandle(hdlReturn: PSomeHandle): Integer;
  iHndl : Integer;

  iHndl := 255; // fake handle
  fHandle := PInteger(iHndl);
  hdlReturn^ := @fHandle;

  Result := 0;

Open in new window

I was doing wrong the assignment to "hdlReturn".
I was missing the caret.

Still I don't know why it works! LOL

I mean, using "var" make sense, I had it worked before I posted here. But I didn't want to use "var".  Also because my fake api would endup different then the real.

fischermxAuthor Commented:
Now, from the calling side, it looks like:

  iHandle : PSomeHandle;


  result := PInteger(iHandle)^;

Open in new window

And that returns my 255 value.
fischermxAuthor Commented:
And here's something more I don't understand.

For the code in the prior post.

If I declare iHandle as PSomeHandle (PPointer), or as SomeHandle (Pointer)...  without changing absolutely nothing... neither in the fake function, nor in the calling side, and  the code still works!!

I don't get it why either a PPointer or a Pointer doesn't matter to get the value back.

I would think the using PPointer would require an extra dereferencing, but it seems it's not needed.

My guess is the compiler is helping somehow.

@ returns a Pointer whatever it's operand is, so it doesn't matter if its operand is Pointer or Integer or something else.
fischermxAuthor Commented:
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.