为什么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。 [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。 解决方法
WideString与BSTR相同,它只是Delphi的名称。内存分配由共享COM分配器CoTaskMemAlloc处理。因为所有各方使用相同的分配器,您可以在一个模块中安全地分配并释放另一个模块。
所以,你不需要使用Sharemem的原因是Delphi堆没有被使用。而是使用COM堆。这是一个进程中所有模块之间共享的。 如果您查看Delphi实现的WideString,您将看到以下API的调用: 您参考的许多Windows API早于COM的发明。此外,使用由调用者分配的固定长度缓冲区具有性能优势。也就是说它可以分配在堆栈而不是堆上。我也可以想象,Windows设计师不想强制每个进程必须链接到OleAut32.dll并支付维护COM堆的代价。请记住,当大多数Windows API被设计时,典型硬件的性能特征与现在非常不同。 没有更广泛使用BSTR的另一个可能的原因是Windows API是针对C的。从C开始,管理BSTR的生命周期要比C,C#,Delphi等更高级的语言更加棘手。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |