1
votes

I´m migrating my Delphi 5 source code to Delphi 10 Berlin. I´ve got many DLLs in my project which export functions. These functions are called from other DLLs. There are two DLLs which I can not migrate to Delphi 10 but I still want to use them in my program. Here an example:

function DoSomething( aList: TStringList ): Boolean; external 'Delphi5.dll';

I want to call "DoSomething" from my Delphi 10 Project. But the problem is, that TStringList in Delphi 5 is not compatible to TStringList in Delphi 10 Berlin (unicode). It would work, when DoSomething would have a parameter like "aString: AnsiString" because AnsiString is compatible to "string" in Delphi 5.

Is there a way to send a List between these two Delphi-Versions? Perhaps a TList or something else? Of course I could send a AnsiString with a separator between the strings to simulate a list, but I want a clean solution, because I´ve got many of these export-functions.

Thanks!

1
The design is majorly flawed. You should never ever ever ever pass objects across DLL boundaries. If it were up to me, I'd completely re-design this to pass the raw data. Perhaps even something along the lines of FindFirst / FindNext. - Jerry Dodge
If your programs ever worked it was only by chance. You'll need to redesign the interface. - David Heffernan
Not to mention, you're using the wrong calling convention. - Jerry Dodge
@Jerry So long as both sides use the same calling convention, it's fine - David Heffernan
The original code and design is not from me. It´s a very big project and I try to migrate it to Delphi 10. I have to live with some design errors because it would take too much time to change them. Passing objects across DLLs works fine in the project. What would be the best way to communicate between DLLs or EXE and DLL. COM? - Sam

1 Answers

4
votes

One should NEVER pass an object reference from an EXE to a DLL if it is meant to be used inside the DLL, or vice versa. An object reference can safely be passed to a DLL only if all the DLL does is pass the object back to the EXE (ro vice versa), such as through a callback function.

As you experienced, an object reference is not valid if the EXE and DLL aren't compiled with the same version of Delphi. Even if they are compiled with the same version, I suspect some compiler options could make them incompatible ({$Align} comes to mind, though I have never verified it). And even then, some incompatibilities might still occur (such as "Cannot assign TStringList to TStringList" errors due to RTTI mismatches).

Something that could fix your issue with minimal changes to your code would be to change the declaration of your functions to pass an interface to the DLL, and create a wrapper around TStringList that supports that interface. Said interface would need to support all the functionality you need from TStringList.

function DoSomething( aList: IStringList ): Boolean

Interfaces can be passed between DLL/EXE without most of the problems related to the object reference (as long as they use the exact same interface definition when they are compiled). (Edit: You still need to ensure the data passed to the interface's method are safe to pass to/from a DLL.)

That said, the interface should explicitly use AnsiString use a null-terminated PAnsiChar, or even a WideString (which can safely be sent to/from DLL - Reference).

function DoSomething( aListText: PAnsiChar ): Boolean

function DoSomething( aListText: WideString ): Boolean

Do not use String, which is AnsiString in Delphi 5 but is UnicodeString is Delphi 10. And don't use AnsiString, as it is not compatible between Delphi 5 and Delphi 10 due to internal structure differences.