将空分隔的PWideChar转换为字符串列表

时间:2017-04-03 11:20:03

标签: delphi delphi-10.1-berlin

从Windows API调用(GetUserPreferredUILanguages()),我得到一个字符串列表 one null-delimited PWideChar。我需要将其转换为Delphi字符串列表。我开始编写代码来手动遍历列表,寻找#0个字符。

有更聪明的方法吗?

PWideChar返回的GetUserPreferredUILanguages示例:

('e','n','-','U','S',#0,'f','r','-','F','R',#0,#0,...)

(基于我在文档中读到的内容,因为当我在计算机上调用该函数时,它只返回一种语言,即'en-US'#0#0)

到目前为止,这是我的代码:

procedure GetWinLanguages(aList: TStringList);
var lCount, lSize: ULong;
    lChars: array of WideChar;
    lIndex, lLastIndex: integer;
begin
  lSize := 1000;
  SetLength(lChars, lSize);
  GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, @lCount, @lChars[0], @lSize);

  // untested quick solution to convert from lChars to aList
  lIndex := 0;
  lLastIndex := -1;
  while (lIndex<=lSize) do
  begin
    while (lIndex<lSize) and (lChars[lIndex]<>#0) do
      inc(lIndex);
    if (lIndex-lLastIndex)>1 then
    begin
      // here: copy range lLastIndex to lIndex, convert to string and add to aList
      lLastIndex := lIndex;
      inc(lIndex);
    end else
      Break;
  end;
end;

PS。我在Windows 10上使用Delphi Berlin进行FMX项目。

2 个答案:

答案 0 :(得分:5)

此API返回以双结尾的字符串。 该程序展示了如何解析这样的事情:

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  Winapi.Windows;

procedure Main;
var
  NumLanguages, LanguagesBufferLen: ULONG;
  LanguagesBuffer: TArray<WideChar>;
  P: PWideChar;
  str: string;
begin
  LanguagesBufferLen := 0;
  Win32Check(GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, @NumLanguages, nil, @LanguagesBufferLen));
  SetLength(LanguagesBuffer, LanguagesBufferLen);
  Win32Check(GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, @NumLanguages, @LanguagesBuffer[0], @LanguagesBufferLen));
  P := @LanguagesBuffer[0];
  while P^<>#0 do begin
    str := P;
    Writeln(str);

    inc(P, Length(str)+1); // step over the string, and its null terminator
  end;
end;

begin
  try
    Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

显而易见的是,如何从此代码中提取一个函数来将以null结尾的字符串解析为字符串列表。这将允许您在其他地方重用代码。

答案 1 :(得分:1)

API返回一个以双重结尾的字符串,其中每个子字符串由#0字符分隔,然后列表以额外的#0字符终止。因此,您只需循环直到遇到最后#0个字符。例如:

procedure GetWinLanguages(aList: TStringList);
var
  lCount, lSize: ULONG;
  lChars: array of Char;
  lStr: PChar;
begin
  lSize := 0;
  lChars := nil;

  repeat
    // unlike most Win32 APIs, GetUserPreferredUILanguages() returns TRUE when
    // pwszLanguagesBuffer is nil and pcchLanguagesBuffer is set to 0 (unless a
    // real error occurs!). This is not made clear in the documentation! The
    // function only returns FALSE with an ERROR_INSUFFICENT_BUFFER error code
    // when pwszLanguagesBuffer is not nil and pcchLanguagesBuffer is set too low...

    if not GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, @lCount, PChar(lChars), @lSize) then
    begin
      if GetLastError() <> ERROR_INSUFFICIENT_BUFFER then
        RaiseLastOSError;
    end
    else if lChars <> nil then
      Break;
    SetLength(lChars, lSize);
  until False;

  lStr := PChar(lChars);
  while (lStr^ <> #0) do
  begin
    aList.Add(lStr);
    Inc(lStr, StrLen(lStr)+1);
  end;
end;