Delphi后Unicode版本:如何正确接收Out LPWSTR值及编码咨询
处理Windows API中LPWSTR输出参数的正确姿势(针对后Unicode版本Delphi)
首先,你遇到的这个问题是Windows API编程里的常见场景,别担心,咱们一步步拆解解决。
一、如何正确分配LPWSTR所需的缓冲区?
Windows API对于字符串输出参数,通常遵循两种标准模式,最稳妥的是先获取所需长度,再分配缓冲区调用——虽然需要两次API调用,但这是官方推荐的做法。针对你担心的“期间长度变化”问题,大部分场景下这种竞态发生的概率极低;如果真遇到动态变化的字符串,也可以通过循环重试来处理,先看标准流程:
标准步骤:
- 第一次调用API获取所需长度:将LPWSTR参数传
nil,同时把缓冲区大小参数设为0,此时API会返回所需的字符长度(注意:多数API返回的长度不包含末尾的\0终止符,所以分配时要额外加1)。 - 分配对应大小的缓冲区:在Delphi中,用
WideString会更方便(自动管理内存),也可以手动用GetMem分配PWChar。 - 第二次调用API获取实际内容:传入分配好的缓冲区和缓冲区大小(长度+1,确保能容纳终止符)。
Delphi代码示例(以GetWindowTextW为例):
用WideString简化内存管理:
var RequiredLen: Integer; OutputStr: WideString; begin // 第一步:获取所需字符串长度(不含终止符) RequiredLen := GetWindowTextW(Handle, nil, 0); if RequiredLen > 0 then begin // 第二步:分配WideString缓冲区,设置长度为所需字符数 SetLength(OutputStr, RequiredLen); // 第三步:调用API获取内容,缓冲区大小要+1以容纳终止符 GetWindowTextW(Handle, PWideChar(OutputStr), RequiredLen + 1); // 此时OutputStr就是完整的结果,可以直接使用 ShowMessage(OutputStr); end; end;
手动管理内存的方式(适合需要精细控制的场景):
var RequiredLen: Integer; OutputPtr: PWChar; begin RequiredLen := GetWindowTextW(Handle, nil, 0); if RequiredLen > 0 then begin // 分配(RequiredLen + 1)个WCHAR的内存,每个WCHAR占2字节 OutputPtr := GetMem((RequiredLen + 1) * SizeOf(WCHAR)); try GetWindowTextW(Handle, OutputPtr, RequiredLen + 1); // 转成WideString使用 ShowMessage(WideString(OutputPtr)); finally // 记得释放内存 FreeMem(OutputPtr); end; end; end;
特殊情况处理:
有些API不会通过传0返回长度,而是当缓冲区不足时返回ERROR_INSUFFICIENT_BUFFER错误码。这时可以先分配一个初始大小的缓冲区(比如1024字符),如果调用失败且错误码是缓冲区不足,再根据返回的所需长度重新分配,循环调用直到成功。不过这种情况相对少见,大部分字符串类API都支持“传0获取长度”的模式。
二、关于Windows API的编码问题
针对后Unicode版本的Windows(从Windows 2000开始的原生Unicode系统),以及后Unicode版本的Delphi(Delphi 2009及以后):
- 所有以
W结尾的API(比如GetWindowTextW)都是使用UTF-16LE编码,LPWSTR本质是指向WCHAR的指针,而WCHAR就是16位的UTF-16字符(小端字节序)。 - Delphi的
WideString类型完全兼容这种编码,它的内部存储就是UTF-16LE,和Windows API的内存布局完全一致,所以你不需要做任何编码转换,直接将LPWSTR转成WideString,或者用PWChar/PWideChar操作即可。 - 注意:如果调用的是
A结尾的ANSI版本API(比如GetWindowTextA),它会使用系统默认的ANSI代码页,这种方式不推荐,因为会有编码丢失问题。后Unicode版本的Delphi默认会调用W版本的API(编译器默认定义了UNICODE宏),所以你不用额外处理。
内容的提问来源于stack exchange,提问作者Alex James




