2017-04-03 64 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

我通常在做這種查詢+爲動態數據分配時循環。由於正在查詢系統數據,並且分別檢索大小和數據,因此循環處理數據可能在檢索大小之後並且在檢索實際數據之前更改的情況。是的,這是一個小小的機會之窗,但它依然存在。 –

相關問題