简体   繁体   中英

Get string return value from C DLL in Delphi

I have a legacy DLL written in C that contains a function that returns a string, and I need to access this function from Delphi. The only info I have about the DLL is the VB declare for accessing the function:

Public Declare Function DecryptStr Lib "strlib" (Str As String) As String

I've tried the following without success:

Declaration:

function DecryptStr(s: PChar): PChar; cdecl; external 'strlib.dll';

Usage:

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 );
  StrPCopy( p2, 'some string to decrypt' );
  p1 := DecryptStr( p2 );
end;

This consistently crashes the DLL with an Access Violation. I'm at a loss.

Any suggestions ?

Consider rewriting your test code as follows:

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 ); // initialize
  GetMem( p2, 255 );
  StrPLCopy( p2, 'some string to decrypt', 255 ); // prevent buffer overrun
  StrPLCopy( p1, DecryptStr( p2 ), 255); // make a copy since dll will free its internal buffer
end;

If still fails within a call to DecryptStr, then read http://support.microsoft.com/kb/187912 carefully.

p2 isn't initialized. StrPCopy copies the string to a random memory location. And most likely the calling convention is stdcall.

I'm guessing here, but are you sure it's cdecl? If the VB declare isn't mentioning it, I'd assume it's in fact a STDCALL function (STDCALL is quite common on Windows, as almost all of its native API uses it). Calling a function of one calling convention as if it were of another calling convention can really mess up the stack, usually leading to a crash.

Also, be sure to check whether the string is ANSI (LPSTR/LPCSTR) or UNICODE (LPWSTR/LPCWSTR). I don't know VB or Delphi, so I don't know what each one uses by default.

As Jozz says, p2 (where you copy your string to) is never initialized in your example.

Try this instead.

var
  p1, p2 : pchar;
begin
  GetMem( p2, 255 ); // allocate memory for 'some string...'
  StrPCopy( p2, 'some string to decrypt' );
  p1 := DecryptStr( p2 );
end;

Also, the memory you allocated by calling Getmem(p1,...) would have been leaked, because p1 was overwritten by the function return from DecryptStr.

However, I'd be a bit concerned about exactly what DecryptStr is returning, and who owns the memory pointed to by p1. If it's returning a pointer to memory allocated by the DLL you will need to be careful how that memory is freed.

I'm dropping in my solution as I've sturggled quite a bit with it and haven't found it in any of the answers.

The C++ function looks like this:

int  __stdcall DoSomething(char * _name);

To get it working in Delphi, I declare the following function

function DoSomething(name: PAnsiChar): integer; stdcall; external 'somedll.dll';

And then when I make the call, I have a function that looks like this:

var s: PAnsiChar;
begin
  GetMem(s, 255);
  DoSomething(s);
  // s now contains the value returned from the C DLL
end;

I have tried using PChar instead of PAnsiChar but all I get in return is garbage. Also, if I declare the function in Delphi with the parameter set to var , I get an exception when I try to read it.

Hope this helps anyone..

I agree with CesarB, try to declare it with stdcall directive as:

function DecryptStr(s: PChar): PChar; stdcall; external 'strlib.dll';

if it doesn't work, post the VB declaration here.

The best way in these kind of situation is to debug your program and check the stack before and after executing the callback. How knows, it might even be a bug in the external DLL?

This way you will see pretty easy how to correct this.

Was the dll written in Borland C or C++Builder by any chance with the intention of being used with Delphi? In which case it could have been compiled using a pascal directive.

The suggestions that the strings must be "initialised" seem to be correct. This is because C will require that the string being passed in is null-terminated. Check that the character in the bufffer just after the end of the text is a null (#0).

Why do you assume that the string passed in is exactly 255 chars long? You need to allocate Length(p1) + 1 bytes - for the chars in p1, and a #0 char at the end.

Also, your code sample seems confused as to the use of p1 and p2. It looks like p1 is the buffer passed to the C DLL, which you allocate, and p2 is the returned string that the DLL allocates. But then the code would be (note use of p1 and p2)

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 );
  StrPCopy( p1, 'some string to decrypt' );
  p2 := DecryptStr( p1 );
end;

Better variable names would help you make this clearer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM