Link to home
Start Free TrialLog in
Avatar of fischermx
fischermxFlag for Mexico

asked on

From C++ to Delphi: several approaches to deal with pointer parameters

I'm writing a piece of code that will interact with a 3rd party C++ library.

In a particular function, for example, the header and function looks like this:
(There are several dozens funcions to call)


SOME_API int CPP_GetSomeValue(int* valueRet);


The function is defined like this:
int CPP_GetSomeValue(int* valueRet);
{
  GetSomeValue(valueRet);
  return 0;
}

Open in new window


Then the function it calls, is defined like this:
int GetSomeValue(int* valueRet)
{
  int val;
  SomeVal(val)
  *valueRet = val;
  return 0;
}

Open in new window


and finally SomeVal is defined like this:
int SomeVal(int& typeRet)
{
  typeRet = 255;	
  return 0;
}

Open in new window



Now, in Delphi, I have my header defined like this:

CPP_GetSomeValue: function (valueRet: PInteger): Integer stdcall;


And finally how should I define and send and get this value back which was filled by the C++

Library?

I found 3 ways to do the same, but I want to know what's the correct way to do it, what are the

difference between them, and possible problems:


1)
The easiest one, just declare an Integer, pass the address, read the value again.

ivalueRet : Integer; 

CPP_GetSomeValue(@ivalueRet);
Result := ivalueRet;

Open in new window


.. though I feel this "risky", doesn't seem safe. but I don't know



2)
Define a PInteger, New it, pass it, derreference it and dispose it      

pvalueRet : Pinteger;

New(pvalueRet); 
CPP_GetSomeValue(pvalueRet);
Result := pvalueRet^;
Dispose(pvalueRet);

Open in new window

(I found this also works to get the value: Result := PInteger(@pvalueRet)^;)




3)
Define a PInteger, but don't initialize it and pass the address:

pvalueRet : Pinteger; 
// Not "new", not "dispose"
CPP_GetSomeValue(@pvalueRet);
Result := Integer(pvalueRet);

Open in new window

(I found this also works to get the value: Result := PInteger(@pvalueRet)^;)

This also looks weird, like I'm just using the pointer to get the integer back.


Which one is the correct? The one that doesn't get me memory leaks, dangling pointers and ugly stuff like that.

ASKER CERTIFIED SOLUTION
Avatar of Ephraim Wangoya
Ephraim Wangoya
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of fischermx

ASKER

Hi, Ewangoya:

Thanks for your reply.

I was using method 1 and 2 in different parts of this project (I'm implementing a dataset for a proprietary data format), but currently I'm getting weird AV's inside DB unit, so I was about to blame either of those for trashing Delphi memory and wanted to decide for one.

I guess the AV in my code are not related to these calls.


Right, its unlikely that this is what is causing the AV.

Why don't you run the program with debug options enabled, then set a break point where you suspect the AV happens then you can step through the code until you get the AV
Yes, I did that.
The AV occurs in an assignment to true to a boolean member of TDataset that is only used as a simple flag... weird, very weird. Memory has been severely damaged.
I've just found out yesterday that the problem only exists when a DBGrid is present. If I just put DBEdit my dataset works fine.
I know a DBGrid causes a lot of "motion" inside the dataset, and somehow, some thing is getting overriden :(

Ewangoya:

Let me ask you something more.
According to what you see in the C++ code and the way I'm calling it from Delphi... should the header be declared in Delphi as "stdcall" or "cdecl"?
That should be stdcall
Hi, Ewangoya:

The AV I was talking about were fixed by changing "stdcall", as I had it, to "cdecl" !
I'm not understand why.

Well, this is was an additional question anyway, thanks for the answer on the parameter handling.
Great! Thank you!