【问题标题】:Sending TStringList between different Delphi versions在不同的 Delphi 版本之间发送 TStringList
【发布时间】:2016-10-12 16:43:46
【问题描述】:

我正在将我的 Delphi 5 源代码迁移到 Delphi 10 Berlin。我的项目中有许多导出功能的 DLL。这些函数是从其他 DLL 调用的。有两个 DLL 我无法迁移到 Delphi 10,但我仍然想在我的程序中使用它们。 举个例子:

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

我想从我的 Delphi 10 项目中调用“DoSomething”。但问题是,Delphi 5 中的 TStringList 与 Delphi 10 Berlin 中的 TStringList 不兼容(unicode)。当 DoSomething 有一个像 "aString: AnsiString" 这样的参数时它会起作用,因为 AnsiString 与 Delphi 5 中的 "string" 兼容。

有没有办法在这两个 Delphi 版本之间发送列表?也许是 TList 或其他东西?当然我可以发送一个带有分隔符的 AnsiString 字符串来模拟一个列表,但我想要一个干净的解决方案,因为我有很多这样的导出函数。

谢谢!

【问题讨论】:

  • 设计存在重大缺陷。您永远不应该跨越 DLL 边界传递对象。如果由我决定,我会完全重新设计它以传递原始数据。甚至可能类似于FindFirst / FindNext
  • 如果您的程序曾经成功,那只是偶然。您需要重新设计界面。
  • 更不用说,你使用了错误的调用约定。
  • @Jerry 只要双方使用相同的调用约定就可以了
  • 原始代码和设计并非来自我。这是一个非常大的项目,我尝试将其迁移到 Delphi 10。我不得不忍受一些设计错误,因为更改它们需要太多时间。跨 DLL 传递对象在项目中工作正常。在 DLL 或 EXE 和 DLL 之间进行通信的最佳方式是什么。 COM?

标签: delphi dll delphi-5 delphi-10.1-berlin


【解决方案1】:

如果要在 DLL 中使用,则永远不应将 EXE 中的对象引用传递给 DLL,反之亦然。只有当 DLL 所做的只是将对象传递回 EXE(反之亦然)时,才能将对象引用安全地传递给 DLL,例如通过回调函数。

如您所见,如果 EXE 和 DLL 不是使用相同版本的 Delphi 编译的,则对象引用无效。即使它们使用相同的版本编译,我怀疑某些编译器选项可能会使它们不兼容(想到{$Align},尽管我从未验证过)。即使这样,仍然可能会出现一些不兼容问题(例如由于 RTTI 不匹配导致的"Cannot assign TStringList to TStringList" 错误)。

可以通过对代码的最小更改来解决您的问题的方法是更改​​函数的声明以将接口传递给 DLL,并围绕支持该接口的TStringList 创建一个包装器。所述接口需要支持TStringList 所需的所有功能。

function DoSomething( aList: IStringList ): Boolean

接口可以在 DLL/EXE 之间传递而不会出现与对象引用相关的大多数问题(只要它们在编译时使用完全相同的接口定义)。 (编辑:您仍然需要确保传递给接口方法的数据可以安全地传递给/从 DLL 传递。

也就是说,接口应该显式使用 AnsiString 使用以 null 结尾的 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之间不兼容,因为内部结构差异。

【讨论】:

  • AnsiString in Berlin 与 Delphi 5 中的 AnsiString 不兼容。其内部结构在 Delphi 2009 中发生了更改。在 DLL 边界上传递任何非 POD 数据类型是不安全的。这包括所有 Delphi 管理的类型,包括 AnsiStringUnicodeString,但不包括 WideString(由操作系统管理,因此可以安全使用)。
  • @RemyLebeau 很好……我相应地更新了我的答案。
  • AnsiString 在使用相同编译器构建的两个模块之间不一定兼容。这也需要一个共享内存管理器。
  • 从来没有?当 DLL 是 Delphi 包时呢?
  • 好吧,我不确定,但我相信如果 DLL 和 EXE 都使用相同的运行时构建,您可以在技术上(例如)在 DLL/EXE 之间传递一个 TStringList 没有问题包含 TStringList 定义的包(以及所有其他依赖包)。但是自从我还是初级开发人员以来,我就没有使用过运行时包。我们遇到了很多问题,以至于我们最终不再使用它们构建 DLL。已经有 10 多年没有使用它们了,所以我可能对此有几点误解。此外,由于您的 DLL 有这么多限制,您最好改为构建 BPL。
猜你喜欢
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 2012-07-07
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-25
相关资源
最近更新 更多