为什么Delphi DLL在不使用ShareMem的情况下使用WideString?

前端之家收集整理的这篇文章主要介绍了为什么Delphi DLL在不使用ShareMem的情况下使用WideString?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
David’s answer to another question显示一个返回WideString的Delphi DLL函数。我从来没有想过没有使用ShareMem是可能的。

我的测试DLL:

function SomeFunction1: Widestring; stdcall;
begin
  Result := 'Hello';
end;

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

我的来电程序:

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 API使用的惯例,例如Windows GetClassNameW:

function GetClassNameW(hWnd: HWND; lpClassName: PWideChar; nMaxCount: Integer): Integer; stdcall;

意思是调用者提供缓冲区和最大长度。 Windows DLL以长度限制写入该缓冲区。调用者分配并释放内存。

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

内存分配和解除分配如何与我的DLL示例一起工作?是否发生“魔术”,因为结果是WideString(BSTR)?为什么不通过这种方便的惯例声明Windows API? (有没有任何已知的Win32 API使用这样的惯例?)

编辑:

我用C#测试过DLL。
调用SomeFunction1会导致AV(尝试读取或写入受保护的内存)。
SomeFunction2工作正常。

[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

@H_403_31@解决方法
WideString与BSTR相同,它只是Delphi的名称。内存分配由共享COM分配器CoTaskMemAlloc处理。因为所有各方使用相同的分配器,您可以在一个模块中安全地分配并释放另一个模块。

所以,你不需要使用Sharemem的原因是Delphi堆没有被使用。而是使用COM堆。这是一个进程中所有模块之间共享的。

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

您参考的许多Windows API早于COM的发明。此外,使用由调用者分配的固定长度缓冲区具有性能优势。也就是说它可以分配在堆栈而不是堆上。我也可以想象,Windows设计师不想强制每个进程必须链接到OleAut32.dll并支付维护COM堆的代价。请记住,当大多数Windows API被设计时,典型硬件的性能特征与现在非常不同。

没有更广泛使用BSTR的另一个可能的原因是Windows API是针对C的。从C开始,管理BSTR的生命周期要比C,C#,Delphi等更高级的语言更加棘手。

猜你在找的Delphi相关文章