为了账号安全,请及时绑定邮箱和手机立即绑定

为什么不能将WideString用作互操作的函数返回值?

为什么不能将WideString用作互操作的函数返回值?

qq_花开花谢_0 2019-07-15 19:12:11
为什么不能将WideString用作互操作的函数返回值?我不止一次建议人们使用类型的返回值。WideString为了互操作的目的。访问DelphiDLL抛出ocasional异常ASP.NET Web应用程序在IIS Web服务器上调用DelphiDLL,返回Pchar字符串时锁定为什么DelphiDLL可以在不使用ShareMem的情况下使用WideString?我的想法是WideString与BSTR..因为BSTR在共享COM堆上分配,那么在一个模块中分配并在另一个模块中释放是没有问题的。这是因为所有各方都同意使用相同的堆,COM堆。然而,似乎WideString不能用作互操作的函数返回值。考虑下面的DelphiDLL。library WideStringTest;uses   ActiveX;function TestWideString: WideString; stdcall;begin   Result := 'TestWideString';end;function TestBSTR: TBstr; stdcall;begin   Result := SysAllocString('TestBSTR');end;procedure TestWideStringOutParam(out str: WideString); stdcall;begin   str := 'TestWideStringOutParam';end;exports   TestWideString, TestBSTR, TestWideStringOutParam;beginend.以及下面的C+代码:typedef BSTR (__stdcall *Func)();typedef void (__stdcall *OutParam)(BSTR &pstr);HMODULE lib = LoadLibrary(DLLNAME);Func TestWideString =  (Func) GetProcAddress(lib, "TestWideString");Func TestBSTR = (Func) GetProcAddress(lib, "TestBSTR");OutParam TestWideStringOutParam = (Out Param) GetProcAddress(lib,                    "TestWideStringOutParam");BSTR str = TestBSTR();wprintf(L"%s\n", str);SysFreeString(str);str = NULL;TestWideSt                    ringOutParam(str);wprintf(L"%s\n", str);SysFreeString(str);str = NULL;str = TestWideString();                    //fails herewprintf(L"%s\n", str);SysFreeString(str);打电话给TestWideString此错误失败:BSTRtest.exe中0x772015de处的未处理异常:0xC0000005:访问冲突读取位置0x00000000。类似地,如果我们尝试用p/Invoke从C#调用它,则会有一个失败:[DllImport(@"path\to\my\dll")][return: MarshalAs(UnmanagedType.BStr)]static extern string TestWideString();错误是:ConsoleApplication10.exe中发生了“System.Runtime.InteropServices.SEHException”类型的未处理异常附加信息:外部组件引发异常。呼叫TestWideStringVia/Invoke按预期工作。因此,使用WideString参数按引用传递,并将它们映射到BSTR似乎运作得很好。但不适用于函数返回值。我已经在Delphi 5,2010和XE2上测试了这一点,并且在所有版本上都观察到了相同的行为。执行进入Delphi,几乎立即失败。分配给Result变成打电话到System._WStrAsg,第一行内容如下:CMP     [EAX],EDX现在,EAX是$00000000当然会有访问违规行为。有人能解释一下吗?我做错什么了吗?我的期望是不是不合理?WideString函数值是可行的BSTR是吗?还是仅仅是德尔菲的缺陷?
查看完整描述

3 回答

?
白衣非少年

TA贡献1155条经验 获得超0个赞

在常规的Delphi函数中,函数返回实际上是一个通过引用传递的参数,即使在语法上它看起来和感觉都像是一个“Out”参数。您可以这样测试它(这可能取决于版本):

function DoNothing: IInterface;begin
  if Assigned(Result) then
    ShowMessage('result assigned before invocation')
  else
    ShowMessage('result NOT assigned before invocation');end;procedure TestParameterPassingMechanismOfFunctions;var
  X: IInterface;begin
  X := TInterfaceObject.Create;
  X := DoNothing; end;

演示呼叫TestParameterPassingMechanismOfFunctions()

您的代码失败是因为Delphi和C+在函数结果传递机制方面对调用约定的理解不匹配。out参数。但对德尔菲来说var参数。

要解决这个问题,请尝试如下:

function TestWideString: WideString; stdcall;begin
  Pointer(Result) := nil;
  Result := 'TestWideString';end;


查看完整回答
反对 回复 2019-07-15
  • 3 回答
  • 0 关注
  • 426 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信