Hello All,

I am having a problem when returning a PChar from a function using Delphi 6. First of all, most of my functions pass type 'strings' around, but I am creating a DLL, to make sure it's universal, i can only pass type 'PChar' in and out of my DLL function. So when I get the 'PChar' from the function call, I change them to strings. I do this because strings are so much easier to work with, and performance with this DLL is not really an issue.
So pressing forward. When I get to the end of my function, I want to to pass the string back out of the function, so I do a PChar(MyString) where MyString is my variable of type string. What happens is when I get the PChar out of my function, I get a ASCII '0' (zero) appended to the end. Inside my function I get no such character. Let me show you the different ways I have tried to pass this PChar:

result := PChar(MyString);

and

MyString := MyString + #0;
result := @MyString[1];

and my function looks like this, MyPChar is of type 'PCHar'

MyPChar := DLLFunction(RandomCrap);

The second on was a long shot, I assume that is what the PChar function does. But I still get a '0' printed to the end of my string.

Any suggestions or comments would help.

That's the way it is supposed to work. PChar is #0 terminated.

I would have to look it up to be sure, but I don't know if Delphi is smart enough to return a string the way you are doing it. The PChar you get from the DLL should be invalid.

The most proper way to do it (without the shared memory manager) would be to have your DLL export two kinds of function:

// type one: returns memory belonging to the DLL
function ReturnsAString: PChar;
function ReturnsAnotherString: PChar;
function ReturnsARecord: PSomeRec;

// type two: tell the DLL you are done with a piece of its memory
procedure FreeString( s: PChar );
procedure FreeSomeRec( r: PSomeRec );

The DLL should be allocating and deallocating dynamic memory to return its strings, etc, and the calling program should get and release access to that memory using the interface functions.

library MyDLL;
uses
  SysUtils;

const
  AString: string = 'Hello world!';

function ReturnsAString: PChar;
  begin
  GetMem( Result, length( AString ) +1 );
  StrPCopy( Result, AString )
  end;

procedure FreeString( s: PChar );
  begin
  FreeMem( s )
  end;

exports
  ReturnsAString,
  FreeString;

begin
end.

And your program should be using it thus:

procedure Button1Click( Sender: Object );  // or whatever
  var
    s: string;
    p: PChar;
  begin
  p := ReturnsAString;  // get the DLL's memory
  s := p;               // get a copy into our string
  FreeString( p );      // return the DLL's memory
  ShowMessage( s )
  end;

Hope this helps.

That's the way it is supposed to work. PChar is #0 terminated.

My PChar string is adding an ASCII '0' to the end of the string. I assume that after the ASCII '0', there is a #0 to terminate the PChar.

I would have to look it up to be sure, but I don't know if Delphi is smart enough to return a string the way you are doing it. The PChar you get from the DLL should be invalid.

One thing that I left out, this seems to happen on sometimes. When the function is first called, the string is passed just fine, but after that I will sometimes get an ASCII 0 at the end of the string. The fact that I'm calling the same function, with the same parameter and get a different result is the most confusing point of the problem. I guess you would say that PChar I get from the DLL is invalid sometimes.

Now, as for allocation memory for the string, then clearing after I get it, this is something that I have not tried and I will look into that.

Thanks for the quick response.

-Karl.

The allocation thing is exactly your problem. The strings you are getting from the DLL are always invalid. :P

Please don't assume anything. A longstring -> PChar will always have a #0 appended, and a PChar -> longstring will always look for the #0 to terminate the string. How exactly are you testing for the #0?

Hope this helps.

How exactly are you testing for the #0?

I am using the PChar function to create the PChar from the string. The PChar is then passed out of the function. I am letting the compilier assume that there is a longstring at the address returned in the PChar. I now understand this is incorrect. I need to allocate memory to the string than then pass that to to the parent application and then destroy the allocated memory.

Well I found the answer to my issue. The problem was that the PChar was pointing to a string, but this string was a function inside my DLL. This was a problem, because Delphi will de-allocate the memory for a function once it is exited. My solution was to create a Global string in my DLL and then point the PChar to that Global. That will stay allocated, even after the function is exited.

This article has been dead for over six months. Start a new discussion instead.