繁体   English   中英

AnsiString从Delphi 2009应用程序中的Delphi 2007 DLL返回值

[英]AnsiString return values from a Delphi 2007 DLL in a Delphi 2009 application

我有一个用D2007编译的DLL,它具有返回AnsiStrings的函数。

我的申请是在D2009编制的。 当它调用AnsiString函数时,它会返回垃圾。

我创建了一个小测试app / dll进行实验,发现如果app和dll都使用相同版本的Delphi(2007或2009)进行编译,则没有问题。 但是当一个在2009年和另一个2007年编译时,我得到了垃圾。

我已经尝试在这两个项目中包含最新版本的FastMM,但即使这样,2009应用程序也无法从2007 dll中读取AnsiStrings。

这里出了什么问题的想法? 有办法解决这个问题吗?

AnsiStrings的内部结构在Delphi 2007和Delphi 2009之间发生了变化。(不要感到沮丧;从第1天起就存在这种可能性。)Delphi 2009字符串维护一个数字,表明其数据所在的代码页。

我建议你做地球上每个其他DLL做的事情,并传递函数可以填充的字符缓冲区。 调用者应传递一个缓冲区指针和一个指示缓冲区大小的数字。 (确保您清楚是否测量字节或字符的大小。)DLL函数填充缓冲区,写入不超过给定大小,计算终止空字符。

如果调用者不知道缓冲区应该有多少字节,那么您有两个选择:

  • 当输入缓冲区指针为空时,使DLL特别表现。 在这种情况下,让它返回所需的大小,以便调用者可以分配那么多空间并再次调用该函数。

  • 让DLL为自己分配空间,使用预定的方法让调用者稍后释放缓冲区。 DLL可以导出用于释放已分配的缓冲区的函数,也可以为调用者指定一些可用的API函数,例如GlobalFree 您的DLL必须使用相应的分配API,例如GlobalAlloc (不要使用Delphi的内置内存分配函数,如GetMemNew ;无法保证调用者的内存管理器将知道如何调用FreeDispose ,即使它是用同一种语言编写的,即使它是用同一种语言编写的。相同的Delphi版本。)

此外,编写只能由单一语言使用的DLL是自私的。 使用与Windows API相同的样式编写DLL,您不会出错。

好吧,所以没有尝试过,所以一个巨大的免责声明打了这个。

在帮助查看器中,查看主题(RAD Stufio中的Unicode)ms-help://embarcadero.rs2009/devcommon/unicodeinide_xml.html

将Delphi 2007字符串返回到Delphi 2009,您应该遇到两个问题。

首先,Rob提到的代码页。 您可以通过声明另一个AnsiString并在新的AnsiString上调用StringCodePage来设置它。 然后通过调用SetCodePage将其分配给旧的AnsiString。 这应该有效,但如果没有,那么仍有希望。

第二个问题是元素大小将是完全疯狂的东西。 它应该是1,所以make it 1.这里的问题是没有SetElementSize函数可以依赖。

尝试这个:

var
  ElemSizeAddr: PWord; // Need a two-byte type
  BrokenAnsiString: AnsiString; // The patient we are trying to cure
...
  ElemSizeAddr := Pointer(PAnsiChar(BrokenAnsiString) - 10);
  ElemSizeAddr^ := 1; // The size of the element

应该这样做!

现在,如果StringCodePage / SetCodePage事件不起作用,您可以执行与上面相同的操作,将我们获取地址的行更改为12而不是10。

它已经乱七八糟地抄写了,这就是我喜欢它的原因。

您最终需要移植这些DLL,但这使端口更易于管理。

最后一句话 - 取决于您如何返回AnsiString(函数结果,输出参数等),您可能需要先将字符串分配给不同的AnsiString变量,以确保内存被覆盖没有问题。

你可能只需要将DLL转换为2009年。根据Embarcadero的说法,转换到2009年是“容易的”,应该没有时间。

就像这里的快速解决方案一样:如果您从字符串中的dll传回的实际数据不超过255个字符,则可以更改in-dll和接口declerations以使用ShortString,无论2007/2009版本如何都可以使用ShortString 。 由于您在2007年使用AnsiString而没有代码页标识符,因此unicode不会给您带来任何麻烦。

如果你这样做,你需要做的就是改变声明,如:

function MyStringReturningFunction : ShortString ; external 'MyLibrary.dll';

(在dll中: function MyStringReturningFunction : ShortString;分别)

当然,输入/输出参数也是如此:

procedure MyStringTakingAndReturningFunction(s1:ShortString; var s2:ShortString); external 'MyLibrary.dll';

应该比更改大量代码更容易。 但要小心,正如我所说,您的数据不得超过255个字符,因为这是ShortString可以容纳的最大大小。

您的DLL不应该以AnsiString值开头。 首先正确工作的唯一方法是,如果DLL和EXE都是使用ShareMem单元编译的,即使这样,只有使用相同的Delphi版本编译它们。 D2007的内存管理器与D2009的内存管理器(或内存管理器的任何其他跨版本使用)AFAIK不兼容。

我同意Rob和Remy的观点:常见的Dll应该返回PAnsiChar而不是AnsiStrings。

如果DLL工作正常用D2009编译,为什么只是不停止用D2007编译它并开始一劳永逸地用D2009编译它?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM