首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Delphi可以使用WideString而不使用ShareMem?

为什么Delphi可以使用WideString而不使用ShareMem?
EN

Stack Overflow用户
提问于 2012-02-17 15:32:06
回答 1查看 6.2K关注 0票数 22

David's answer to another question显示一个Delphi函数返回一个WideString。我从来没有想过,如果不使用ShareMem,这是可能的。

我的测试DLL:

代码语言:javascript
复制
function SomeFunction1: Widestring; stdcall;
begin
  Result := 'Hello';
end;

function SomeFunction2(var OutVar: Widestring): BOOL; stdcall;
begin
  OutVar := 'Hello';
  Result := True;
end;

我的来电者程序:

代码语言:javascript
复制
function SomeFunction1: WideString; stdcall; external 'Test.dll';
function SomeFunction2(var OutVar: Widestring): BOOL; stdcall; external 'Test.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
  W: WideString;
begin
  ShowMessage(SomeFunction1);
  SomeFunction2(W);
  ShowMessage(W);
end;

它工作,我不明白它是如何工作的。我知道的约定是Windows使用的约定,例如Windows

代码语言:javascript
复制
function GetClassNameW(hWnd: HWND; lpClassName: PWideChar; nMaxCount: Integer): Integer; stdcall;

这意味着调用方提供缓冲区和最大长度。带有长度限制的Windows DLL写入该缓冲区。调用方将分配和释放内存。

另一个选项是DLL通过使用LocalAlloc分配内存,调用方通过调用LocalFree来释放内存。

内存分配和取消分配如何与我的DLL示例一起工作?“魔术”的发生是因为结果是WideString(BSTR)吗?为什么没有这样方便的约定来声明Windows呢?(是否有任何已知的Win32 API使用这种约定?)

编辑:

我用C#测试了DLL。

调用SomeFunction1会导致AV (Attempted to read or write protected memory)。

SomeFunction2工作得很好。

代码语言:javascript
复制
[DllImport(@"Test.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string SomeFunction1();

[DllImport(@"Test.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SomeFunction2([MarshalAs(UnmanagedType.BStr)] out string res);

...

string s;
SomeFunction2(out s);
MessageBox.Show(s); // works ok
MessageBox.Show(SomeFunction1()); // fails with AV!

这是一个followup

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-02-17 15:35:09

WideStringBSTR是一样的,它只是Delphi的名字。内存分配由共享COM分配器CoTaskMemAlloc处理。因为所有各方都使用相同的分配器,所以您可以安全地在一个模块中分配,而在另一个模块中释放。

所以,您不需要使用Sharemem的原因是没有使用德尔菲堆。相反,使用COM堆。这是一个过程中所有模块之间的共享。

如果您查看WideString的Delphi实现,您将看到对以下API的调用:SysAllocStringLenSysFreeStringSysReAllocStringLen。这些是提供BSTR API functions的系统。

您所指的许多Windows都是在COM发明之前的.更重要的是,使用由调用方分配的固定长度缓冲区有性能上的好处。也就是说,它可以在堆栈上而不是堆上分配。我还可以想象,Windows设计人员不想强迫每个进程都必须链接到OleAut32.dll,并为维护COM堆付出代价。请记住,当大多数Windows被设计时,典型硬件的性能特征与现在非常不同。

不更广泛地使用BSTR的另一个可能的原因是Windows是针对C的,从C管理BSTR的生存期要比使用C++、C#、Delphi等高级语言复杂得多。

然而,还有一个额外的并发症。用于WideString返回值的Delphi与Microsoft不兼容。不应将WideString用作返回类型,而应通过out参数返回它。有关详细信息,请参阅Why can a WideString not be used as a function return value for interop?

票数 29
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9331026

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档