2016-10-12 11 views
1

Я переношу свой исходный код Delphi 5 в Delphi 10 Berlin. У меня есть много DLL в моем проекте, которые экспортируют функции. Эти функции вызывают из других DLL. Есть две библиотеки DLL, которые я не могу перенести на Delphi 10, но я все еще хочу использовать их в своей программе. Вот пример:Отправка TStringList между различными версиями Delphi

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

Я хочу назвать "DoSomething" из моего Delphi 10 проекта. Но проблема в том, что TStringList в Delphi 5 не совместим с TStringList в Delphi 10 Berlin (unicode). Он работал бы, когда у DoSomething был бы такой параметр, как «aString: AnsiString», потому что AnsiString совместим с «string» в Delphi 5.

Есть ли способ отправить список между этими двумя Delphi-версиями? Возможно, TList или что-то еще? Конечно, я могу отправить AnsiString с разделителем между строками для имитации списка, но я хочу чистое решение, потому что у меня есть много этих экспортных функций.

Спасибо!

+1

Дизайн сильно испорчен. Вы никогда не должны когда-либо пропускать объекты через границы DLL. Если бы это зависело от меня, я бы полностью перепроектировал это, чтобы передать необработанные данные. Возможно, даже что-то вроде «FindFirst»/'FindNext'. –

+0

Если ваши программы когда-либо работали, это было только случайно.Вам нужно будет перепроектировать интерфейс. –

+0

Не говоря уже о том, что вы используете неправильное соглашение о вызове. –

ответ

4

. НИКОГДА НИКОГДА не следует передавать ссылку на объект из EXE в DLL, если она предназначена для использования внутри DLL, или наоборот. Ссылка на объект может быть безопасно передана в DLL только в том случае, если вся DLL передает объект обратно в EXE (ro наоборот), например, через функцию обратного вызова.

Как вы испытали, ссылка на объект недействительна, если EXE и DLL не скомпилированы с той же версией Delphi. Даже если они скомпилированы с той же версией, я подозреваю, что некоторые параметры компилятора могут сделать их несовместимыми ({$Align} приходит на ум, хотя я никогда не проверял его). И даже тогда могут возникнуть некоторые несовместимости (например, ошибки "Cannot assign TStringList to TStringList" из-за несоответствий RTTI).

Что-то, что могло бы исправить вашу проблему с минимальными изменениями в вашем коде, было бы изменить объявление своих функций для передачи интерфейса DLL и создать обертку вокруг TStringList, которая поддерживает этот интерфейс. Указанный интерфейс должен поддерживать все необходимые функции от TStringList.

function DoSomething(aList: IStringList): Boolean 

Интерфейсы могут передаваться между DLL/EXE без большинства проблем, связанных с ссылкой на объект (до тех пор, как они используют то же точное определение интерфейса, когда они составлены). (Edit:. Вы все еще должны обеспечить данные, передаваемые методу интерфейса безопасно передавать в/из DLL)

Тем не менее, интерфейс должен явно использовать AnsiString использовать завершающий нуль PAnsiChar, или даже WideString (который можно безопасно отправлять в/из DLL - Reference).

function DoSomething(aListText: PAnsiChar): Boolean 

function DoSomething(aListText: WideString): Boolean 

Не используйте String, который в Delphi 5 AnsiString но это UnicodeString является Delphi 10. И не используют AnsiString, так как она не совместима между Delphi 5 и Delphi 10 из-за различий в внутренней структуре.

+3

'AnsiString' в Берлине НЕ совместим с' AnsiString' в Delphi 5. Его внутренняя структура была изменена в Delphi 2009. Небезопасно передавать любой тип данных, отличных от POD, через DLL граница. Это включает все управляемые Delphi типы, включая 'AnsiString' и' UnicodeString', но не 'WideString' (который управляется ОС и, следовательно, безопасен в использовании). –

+0

@RemyLebeau Хорошая добыча ... Я обновил свой ответ соответственно. –

+0

'AnsiString' не обязательно совместим между двумя модулями, построенными с одним и тем же компилятором. Для этого также потребуется менеджер разделяемой памяти. –