2017-04-03 61 views
1

从Windows API调用(GetUserPreferredUILanguages())中,我得到一个字符串列表一个零空格分隔PWideChar。我需要将其转换为Delphi字符串列表。我开始编写代码来手动循环遍历列表,寻找#0字符。将空分隔的PWideChar转换为字符串列表

有没有更聪明的方法来做到这一点?通过GetUserPreferredUILanguages返回PWideChar

例子:

('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项目。

+0

对于downvoter:请让我知道这个问题有什么问题。我很乐意改进它。 – Hans

回答

4

此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. 

这应该是显而易见如何从这个代码提取函数来分析一个空值终止字符串字符串列表。这将允许您在其他地方重新使用该代码。

+0

谢谢。是的,我知道它返回了什么。我把它称为一个空分隔的PWideChar,这在技术上就是这样。你的循环比我的更简单 - 我喜欢那个。 – Hans

+0

对不起,我误解了你的代码。我虽然有一个PWideChar –

+0

@Hans数组,但它在技术上是一个** double ** null终止的字符串,而不是一个** single ** null终止的字符串,就像您不断描述的那样。 A ** double **以null结尾的字符串是由空字符分隔的字符串列表,然后该列表由* extra * null字符终止。所以最后有**两个**空值。 –

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; 
+0

此行为在MSDN文档中未明确表示。就这样吧。我相应地修复了代码。 –

+0

你为什么会循环? –

+0

我通常在做这种查询+为动态数据分配时循环。由于正在查询系统数据,并且分别检索大小和数据,因此循环处理数据可能在检索大小之后并且在检索实际数据之前更改的情况。是的,这是一个小小的机会之窗,但它依然存在。 –

相关问题