我有一个Delphi 7应用程序,该应用程序需要调用对于可用的SOAP导入器来说太新的SOAP API。我对自己感到满意的是,如果不付出太多努力,D7就无法调用SOAP API。但是我也有Delphi XE2,它可以导入SOAP并相当高兴地调用它。因此,我在XE2中编写了一个简单的dll包装器,公开了soap接口的必要部分。我可以从XE程序调用dll。在Delphi7中,我从XE中提取了SOAP API导入文件,去掉了{$ SCOPED_ENUMS ON}定义和初始化部分,该部分调用了不可用的SOAP包装器,并在整个过程中将字符串更改为widestring。编译。我使用启用了ShareMM的FastMM来使字符串传递工作并避免进行所有stdcall。我尝试以这种方式进行操作的原因是,如果它能正常工作,它将使SOAP垫片非常容易编码和维护,因为90%的代码是由XE2 SOAP导入程序生成的,这意味着当我们将D7应用程序转移到现代的Delphi中,代码将基本保持不变。但是,当我运行它时,我得到了奇怪的字符串(以及随之而来的访问冲突)。我有一些简单的函数,它们不使用SOAP代码使问题更加明显。从Delphi7 exe传递一个宽字符串到DelphiXE2 dll中,字符串长度加倍(根据Length()函数),但是没有匹配的数据转换。因此,D7中的宽字符串“ 123”在XE2中变为“ 1234 ....”,其中....就是堆栈上发生的任何垃圾。被视为字节数组的两个字节都具有预期的半零字节。从XE2 dll返回一个宽字符串到D7,我得到了镜像效果-字符串长度减半,字符串被简单地截断(“ 1234”变成“ 12”)。我要粘贴代码,因为我知道您会要求它。在Delphi XE2中,我正在导出以下功能:// testingfunction GetString(s:string):string; export;function AddToString(s:string):string; export;implementationfunction GetString(s:string):string;begin Result := '0987654321';end;function AddToString(s:string):string;begin Result := s + '| ' + IntToStr(length(s)) + ' there is more';end;在Delphi 7中:function GetString(s:widestring):widestring; external 'SMSShim.dll';function AddToString(s:widestring):widestring; external 'SMSShim.dll';procedure TForm1.btnTestGetClick(Sender: TObject);var s: widestring;begin s := widestring('1234'); Memo1.Lines.Add(' GetString: ' + GetString(s));end;procedure TForm1.btnTestAddClick(Sender: TObject);var s: widestring;begin s := widestring('1234567890'); Memo1.Lines.Add(' AddToString: ' + AddToString('1234567890'));end;我可以从任一侧运行,使用D7可执行文件作为主机应用程序调试dll。在调试器中检查参数和返回值可得出以上结果。烦人的是,如果我将delphi7中的导入声明为字符串,则会得到正确的长度但无效的数据。如图所示,当我尝试返回时,声明获得了有效的数据,错误的长度和访问冲突。使其全部成为stdcall并不会改变其行为。显而易见的解决方案是只编写简单的包装器函数,即可确切地显示我现在需要的功能。我可以做到,但是我更喜欢上面的狡猾方式。 最佳答案 有问题的DLL导出期望接收UnicodeString参数的函数。 (如您所知,string类型在Delphi 2009中成为UnicodeString的别名。)Delphi 7应用程序无法使用该DLL。运行时库不知道如何对该类型进行操作,因为它早在2002年Delphi 7发布时就不存在。尽管UnicodeString的字符大小与WideString兼容,但它们不是同一类型。 UnicodeString的结构类似于新的AnsiString,因此它具有长度字段,引用计数,字符大小和代码页。 WideString有一个长度字段,但是它携带的任何其他元数据均未记录。 WideString只是Delphi公开COM BSTR类型的方式。遵循的一般规则是,永远不要导出C.1无法使用的DLL函数。特别是,这意味着对于任何函数参数和返回类型,仅使用C兼容类型,因此string是可用的,但是安全的,因为它的WideString根源。将DLL更改为使用BSTR而不是WideString作为其参数。1保持C兼容性还意味着使用C支持的调用约定。 Microsoft C不支持Delphi的默认string调用约定,因此请改用register或cdecl,就像您在曾经使用过的每个Windows DLL中所看到的一样。
10-08 13:29