You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Delphi后Unicode版本:如何正确接收Out LPWSTR值及编码咨询

处理Windows API中LPWSTR输出参数的正确姿势(针对后Unicode版本Delphi)

首先,你遇到的这个问题是Windows API编程里的常见场景,别担心,咱们一步步拆解解决。

一、如何正确分配LPWSTR所需的缓冲区?

Windows API对于字符串输出参数,通常遵循两种标准模式,最稳妥的是先获取所需长度,再分配缓冲区调用——虽然需要两次API调用,但这是官方推荐的做法。针对你担心的“期间长度变化”问题,大部分场景下这种竞态发生的概率极低;如果真遇到动态变化的字符串,也可以通过循环重试来处理,先看标准流程:

标准步骤:

  1. 第一次调用API获取所需长度:将LPWSTR参数传nil,同时把缓冲区大小参数设为0,此时API会返回所需的字符长度(注意:多数API返回的长度不包含末尾的\0终止符,所以分配时要额外加1)。
  2. 分配对应大小的缓冲区:在Delphi中,用WideString会更方便(自动管理内存),也可以手动用GetMem分配PWChar
  3. 第二次调用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

火山引擎 最新活动