Jump to content
shineworld

Interfacing Unicode string to DLL PAnsiChar

Recommended Posts

Posted (edited)

Hi to all,

 

I've moved a lot of code from BDS2006 to Sydney and now it's time to finish DLL interfacing.
Support DLLs are at moment in AnsiString so input parameters are as PAnsiChar, but overall calling

code is ready to use Unicode strings (I'm waiting the right time to convert the DLL).

When strings are emptied a nil pointer must be sent to DLL arguments.

As a workaround I've two solutions, one fine to see but I don't know if will work in all cases.
The second way could work fine always:
 

{ first mode }
function StringToAnsiCPointer(const S: string): PAnsiChar; inline;

function StringToAnsiCPointer(const S: string): PAnsiChar;
begin
  if Length(S) = 0 then
    Result := nil
  else
    Result := PAnsiChar(AnsiString(S));
end;

function CompilerEncryptFile(const TextFileName: string; Key: TCNCEncryptKey; const EncryptedFileName: string): Longint;
begin
  Result := _CompilerEncryptFile	// DLL CALL
  (
    StringToAnsiCPointer(TextFileName),
    @Key,
    StringToAnsiCPointer(EncryptedFileName)
  );
end;

{ SECOND MODE }

function CompilerEncryptFile(const TextFileName: string; Key: TCNCEncryptKey; const EncryptedFileName: string): Longint;
begin
  Result := _CompilerEncryptFile
  (
    IIf(Length(TextFileName) = 0, nil, PAnsiChar(AnsiString(TextFileName))),
    @Key,
    IIf(Length(EncryptedFileName) = 0, nil, PAnsiChar(AnsiString(EncryptedFileName)))
  );
end;

 

My dubs in the first mode are concerning the LIFE of temporary cast to AnsiString in the line:
PAnsiChar(AnsiString(S) as a result of the external function.

Do you have some ideas about it?

Edited by shineworld

Share this post


Link to post
Posted (edited)

Your 1st approach using StringToAnsiCPointer() will never work, since the AnsiString will go out of scope and be destroyed before the PAnsiChar pointer can be passed to the DLL.

 

Your second approach using an AnsiString typecast at the call site will work fine, though you don't actually need the Length() check at all since an AnsiString consists of a nil pointer when empty, so you can just use that inner pointer as-is, by type-casting the AnsiString to a Pointer before casting to PAnsiChar, eg:

function CompilerEncryptFile(const TextFileName: string; Key: TCNCEncryptKey; const EncryptedFileName: string): Longint;
begin
  Result := _CompilerEncryptFile
  (
    PAnsiChar(Pointer(AnsiString(TextFileName))),
    @Key,
    PAnsiChar(Pointer(AnsiString(EncryptedFileName)))
  );
end;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
1 minute ago, Remy Lebeau said:

Your 1st approach using StringToAnsiCPointer() will not work, since the AnsiString will go out of scope and be destroyed before the PAnsiChar pointer can be passed to the DLL.

Wouldn't the inline declaration solve this problem?

Share this post


Link to post
1 minute ago, dummzeuch said:

Wouldn't the inline declaration solve this problem?

Oh, I didn't notice that directive.

 

I don't know if it will work, though.  I rarely ever use inlining.

Share this post


Link to post
16 minutes ago, dummzeuch said:

Wouldn't the inline declaration solve this problem?

Don't rely on whether or not a function is inlined in order for the code to work. After all, it might not be possible to inline it.

  • Like 3

Share this post


Link to post

Thanks all for the help.
The suggested way working perfectly !!!

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×