David's answer to another question显示一个Delphi函数返回一个WideString。我从来没有想过,如果不使用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使用的约定,例如Windows
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工作得很好。
[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。
发布于 2012-02-17 15:35:09
WideString和BSTR是一样的,它只是Delphi的名字。内存分配由共享COM分配器CoTaskMemAlloc处理。因为所有各方都使用相同的分配器,所以您可以安全地在一个模块中分配,而在另一个模块中释放。
所以,您不需要使用Sharemem的原因是没有使用德尔菲堆。相反,使用COM堆。这是一个过程中所有模块之间的共享。
如果您查看WideString的Delphi实现,您将看到对以下API的调用:SysAllocStringLen、SysFreeString和SysReAllocStringLen。这些是提供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?
https://stackoverflow.com/questions/9331026
复制相似问题