gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 14:32:38 27 4
gpt4 key购买 nike

我不止一次建议人们使用 WideString 类型的返回值来实现互操作目的。

这个想法是 WideStringBSTR 相同。 。因为 BSTR 是在共享 COM 堆上分配的,所以在一个模块中分配并在不同模块中释放是没有问题的。这是因为各方都同意使用相同的堆,即 COM 堆。

但是,WideString 似乎不能用作互操作的函数返回值。

考虑以下 Delphi DLL。

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;

begin
end.

以及以下 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 = (OutParam) GetProcAddress(lib,
"TestWideStringOutParam");

BSTR str = TestBSTR();
wprintf(L"%s\n", str);
SysFreeString(str);
str = NULL;

TestWideStringOutParam(str);
wprintf(L"%s\n", str);
SysFreeString(str);
str = NULL;

str = TestWideString();//fails here
wprintf(L"%s\n", str);
SysFreeString(str);

TestWideString 的调用失败并出现以下错误:

Unhandled exception at 0x772015de in BSTRtest.exe: 0xC0000005: Access violation reading location 0x00000000.

同样,如果我们尝试使用 p/invoke 从 C# 调用此函数,则会失败:

[DllImport(@"path\to\my\dll")]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string TestWideString();

错误是:

An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in ConsoleApplication10.exe

Additional information: External component has thrown an exception.

通过 p/invoke 调用 TestWideString 可以按预期工作。

因此,使用 WideString 参数传递引用并将它们映射到 BSTR 似乎效果很好。但不适用于函数返回值。我已在 Delphi 5、2010 和 XE2 上对此进行了测试,并在所有版本上观察到相同的行为。

执行进入 Delphi 后几乎立即失败。对 Result 的赋值变成对 System._WStrAsg 的调用,其第一行内容如下:

CMP     [EAX],EDX

现在,EAX$00000000,自然存在访问冲突。

有人能解释一下吗?难道我做错了什么?我期望 WideString 函数值是可行的 BSTR 是不合理的吗?或者这只是德尔福的缺陷?

最佳答案

在常规的 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++ 对与函数结果传递机制相关的调用约定的理解不匹配,因此您的代码失败。在 C++ 中,函数返回的行为就像语法所示:一个 out 参数。但对于 Delphi 来说,它是一个 var 参数。

要修复,请尝试以下操作:

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

关于delphi - 为什么 WideString 不能用作互操作的函数返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9349530/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com