我有一个用D2007编译的DLL,它有返回AnsiStrings的函数。
我的申请是在D2009编制的。当它调用AnsiString函数时,它会返回垃圾。
我创建了一个小测试app / dll进行实验,发现如果app和dll都使用相同版本的Delphi(2007或2009)进行编译,则没有问题。但是当一个在2009年和另一个2007年编译时,我就会变成垃圾。
我尝试在两个项目中都包含最新版本的FastMM,但即便如此,2009年的应用程序也无法从2007 dll中读取AnsiStrings。
关于这里出了什么问题的任何想法?有办法解决这个问题吗?
答案 0 :(得分:11)
AnsiStrings的内部结构在Delphi 2007和Delphi 2009之间发生了变化。(不要感到沮丧;从第1天起就存在这种可能性。)Delphi 2009字符串维护一个数字,表明其数据所在的代码页。 / p>
我建议你做地球上每个其他DLL做的事情并传递函数可以填充的字符缓冲区。调用者应传递一个缓冲区指针和一个指示缓冲区大小的数字。 (确保你清楚是否要测量字节或字符的大小。)DLL函数填充缓冲区,写入不超过给定的大小,计算终止空字符。
如果调用者不知道缓冲区应该有多少字节,那么你有两个选择:
当输入缓冲区指针为空时,使DLL特别表现。在这种情况下,让它返回所需的大小,以便调用者可以分配那么多空间并再次调用该函数。
让DLL为自己分配空间,使用预定的方法让调用者稍后释放缓冲区。 DLL可以导出用于释放已分配的缓冲区的函数,也可以为调用者指定一些可用的API函数,例如GlobalFree
。您的DLL必须使用相应的分配API,例如GlobalAlloc
。 (不要使用Delphi的内置内存分配函数,如GetMem
或New
;不能保证调用者的内存管理器知道如何调用Free
或Dispose
即使它是用相同的语言编写的,即使它是用相同的Delphi版本编写的。)
此外,编写只能由单一语言使用的DLL是自私的。用与Windows API相同的样式编写DLL,你就不会出错。
答案 1 :(得分:2)
好的,所以没有尝试过,所以一个巨大的免责声明打了一个。
在帮助查看器中,查看主题(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变量,以确保内存被覆盖没有问题。 / p>
答案 2 :(得分:0)
你可能只需要将DLL转换为2009年。根据Embarcadero的说法,转换到2009年是“容易的”,应该没有时间。
答案 3 :(得分:0)
您的DLL不应该首先返回AnsiString值。首先正确工作的唯一方法是,如果DLL和EXE都是使用ShareMem单元编译的,即使这样,只有使用相同的Delphi版本编译它们。 D2007的内存管理器与D2009的内存管理器(或内存管理器的任何其他跨版本使用),AFAIK不兼容。
答案 4 :(得分:0)
我同意Rob和Remy的观点:常见的Dlls应该返回PAnsiChar AnsiStrings。
如果DLL工作正常用D2009编译,为什么不停止编译它 使用D2007并开始一劳永逸地用D2009进行编译?
答案 5 :(得分:0)
这里只是一个快速的解决方案:如果你从字符串中的dll传回的实际数据不超过255个字符,你可以更改in-dll和接口declerations以使用ShortString,这将无论2007年如何都可以使用/ 2009版。由于您在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可以容纳的最大大小。