shineworld 73 Posted June 21, 2021 (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 June 21, 2021 by shineworld Share this post Link to post
Remy Lebeau 1436 Posted June 21, 2021 (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 June 21, 2021 by Remy Lebeau 1 Share this post Link to post
dummzeuch 1517 Posted June 21, 2021 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
Remy Lebeau 1436 Posted June 21, 2021 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
David Heffernan 2353 Posted June 21, 2021 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. 2 Share this post Link to post
shineworld 73 Posted June 22, 2021 Thanks all for the help. The suggested way working perfectly !!! Share this post Link to post