- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
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
来分配内存,而调用者则通过调用 LocalFree
来释放内存。
内存分配和释放如何与我的 DLL 示例一起工作? “魔法”发生是因为结果是 WideString
(BSTR
) 吗?为什么 Windows API 不使用如此方便的约定来声明? (是否有任何已知的 Win32 API 使用此类约定?)
编辑:
我用 C# 测试了 DLL。
调用 SomeFunction1
会导致 AV(尝试读取或写入 protected 内存
)。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 .
最佳答案
WideString
与 BSTR
相同,只是它的 Delphi 名称。内存分配由共享 COM 分配器 CoTaskMemAlloc
处理。因为所有各方都使用相同的分配器,所以您可以安全地在一个模块中分配并在另一个模块中取消分配。
因此,您不需要使用 Sharemem
的原因是 Delphi 堆没有被使用。相反,使用 COM 堆。这是在进程中的所有模块之间共享的。
如果您查看 WideString 的 Delphi 实现,您将看到对以下 API 的调用:SysAllocStringLen
, SysFreeString
和 SysReAllocStringLen
。这些是系统提供的BSTR
API functions .
您提到的许多 Windows API 早于 COM 的发明。此外,使用由调用者分配的固定长度缓冲区具有性能优势。也就是说,它可以分配在堆栈上而不是堆上。我还可以想象 Windows 设计者不想强制每个进程都必须链接到 OleAut32.dll 并付出维护 COM 堆的代价。请记住,当设计大多数 Windows API 时,典型硬件的性能特征与现在有很大不同。
不更广泛地使用 BSTR
的另一个可能原因是 Windows API 是针对 C 的。并且从 C 管理 BSTR
的生命周期比管理要棘手得多来自 C++、C#、Delphi 等高级语言。
但是还有一个额外的复杂情况。 WideString
返回值的 Delphi ABI 与 Microsoft 工具不兼容。您不应使用 WideString
作为返回类型,而应通过 out
参数返回它。欲了解更多详情,请参阅Why can a WideString not be used as a function return value for interop?
关于delphi - 为什么Delphi DLL可以使用WideString而不使用ShareMem?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9331026/
我想将虚拟键转换为 WideString。这就是我到目前为止所拥有的...... function VKeytoWideString (Key : Word) : WideString; var W
我有一个在 Windows 中显示气球托盘的函数,它的结构也是这样的: const NIF_INFO = $00000010; NIIF_NONE = $00
我有以下无法编译的代码片段: procedure Frob(const Grob: WideString); var s: WideString; begin s := Gr
我不止一次建议人们使用 WideString 类型的返回值来实现互操作目的。 Accessing Delphi DLL throwing ocasional exception ASP.NET web
我使用此过程将 key 枚举到 Delphi 7 中的 TNTListView (UNICODE) procedure TForm1.TntButton1Click(Sender: TObject);
我有一个文本,需要将其存储在 widestring 变量中。但我的文本是UTF8,而widestring不支持UTF8并将其转换为一些汉字。 WIDESTRING 有 UTF8 版本吗? 我总是使用U
我正在编写一个类,它将宽字符串保存到二进制文件中。我正在使用 Delphi 2005,但该应用程序稍后将移植到 Delphi 2010。我在这里感到非常不确定,有人可以确认一下吗: Delphi 20
该接口(interface)位于_TLB.pas文件 // *********************************************************************/
我正在尝试构建一个(测试)WideString: á (U+00E1 Small Letter Latin A with acute) 但是使用它的分解形式: LATIN SMALL LETTER A
德尔福有一个WrapText功能: function WrapText(const Line, BreakStr: string; const BreakChars: TSysCharSet; Max
如何将 PAnsiChar 变量转换为 WideString 或 string? 最佳答案 您只需将一个变量分配给另一个变量,然后让 Delphi 编译器为您完成所有转换: var p: PAns
在 C++Builder 中,我编写了以下代码(在 Button1Click 处理程序中),当我在 Debug模式下运行时,我得到“Int3 DbgBreakPoint”(堆栈已损坏?)。 AnsiS
(因为我还没有足够的声望来回答我自己的问题,所以我先把它放在这里。我发布它的时候没有想清楚。对我来说是凌晨 3 点,没有发生让我去别处寻找问题。 我正在创建另一个函数来在 lua 中动态添加一个对象,
我使用delphi 7。 我需要逐行读取一个utf-8文件,每行包含一个单词及其权重(一个数字)因此,我需要读取下一行,然后用分隔符(制表符)分隔行并将其保存在内存中。 所以, 1) Delphi 中
我有一个包含一些数据的 WideString 变量,但是当为字符串分配一些额外的空值时,这些空值或多或少地添加在数据中的随机位置。我现在需要从变量中去除这些空值。如果它是一个字符串,我会检查每个 Ch
我有非常旧的代码(来自 D3): TMyRecord = record Index : Integer; Header : String[70]; Strings : Array[
我有这个代码(我需要将字符串对象添加到 TStringList): var WS: WideString; begin WS := 'allocated string'; SL.AddOb
我很好奇这段代码在 Delphi 2010 中会发生什么: function foo: WideString; var myUnicodeString: UnicodeString; begin
我试图从用 Delphi 编写的 EXE 中接收信息。 EXE 向我传递了一个指向其数据结构之一的指针: Type RecordType = Record St: WideString
我有一种情况需要比较 char* 和 WideString。 如何在 C++ 中将 WideString 转换为 char*? 最佳答案 您可以使用 wcstombs 函数。 size_t wcsto
我是一名优秀的程序员,十分优秀!