FreePascal:如何在非拉丁Windows中使用GetEnvironmentVariable?

时间:2017-12-01 06:59:31

标签: windows encoding lazarus freepascal

我一直在使用Lazarus 1.6.4和FPC 3.0.2编写一些代码来获取Windows中的USERNAME和Linux中的USER。为实现这一点,我使用了SysUtils.GetEnvironmentVariable函数。在Linux中,它工作得很完美,但在Windows中它会返回一些损坏的东西,看起来像UTF8字符串以错误的编码方式打开。我在Windows中的USERNAME具有西里尔符号,因此GetEnvironmentVariable不是实际名称,而是返回????????,但它应该是Пользователь。 这是我的代码:

function GetUserName: string;
{$IFDEF MSWINDOWS}
const
  envVar = 'USERNAME';
{$ENDIF}
{$IFDEF UNIX}
  envVar = 'USER';
{$ENDIF}
begin
  Result := SysUtils.GetEnvironmentVariable(envVar);
{$IFDEF MSWINDOWS}
  { TODO : BUG: Does not work correct for non-latin strings }
  Result := LazUTF8.UTF8ToWinCP(Result)
{$ENDIF}
end;

当它包含非latain符号时,它会返回损坏的字符串。

如何在Windows操作系统中以正确的编码GetEnvironmentVariable?

2 个答案:

答案 0 :(得分:0)

在Windows上使用unicodestring重载3.0+ getenvironmentvariable中的Afaik,并使用-W变体。

var res,tag : unicodestring;

begin
  tag:='HOME';
  res:=getenvironmentvariable(tag);
end;

只是

  getenvironmentstring (unicodestring('whatever'));

也可以,但请确保将utf8设置为默认编码,或将结果分配给unicodestring。

答案 1 :(得分:-1)

经过一天的运行后,我找到了适合我的解决方案。您应该使用SysUtils.GetEnvironmentVariable的Unicode版本并将结果转换为Windows当前代码页。这里的代码如下:

uses
  {$IFDEF MSWINDOWS}
  LazUTF8
  {$ENDIF}
  ;

function GetUserName: string;
const
  envVar: UnicodeString =
{$IFDEF MSWINDOWS}
  'USERNAME'
{$ENDIF}
{$IFDEF UNIX}
  'USER'
{$ENDIF};
begin
  // USE Unicode String Version only!
  Result := SysUtils.GetEnvironmentVariable(envVar);
{$IFDEF MSWINDOWS}
  Result := LazUTF8.UTF8ToWinCP(Result)
{$ENDIF}
end;    

更新01.12.2017 我的解决方案取决于大卫在评论中提到的ENV。在讨论过程中,我找到了更可靠的解决方案here。以下代码:

function GetCurrentUserName: String;

{$IFDEF WINDOWS}
const
  MaxLen = 256;
var
  Len: DWORD;
  WS: WideString;
  Res: windows.BOOL;
{$ENDIF}
begin
  Result := '';
  {$IFDEF UNIX}
  {$IF (DEFINED(LINUX)) OR (DEFINED(FREEBSD))}
  Result := SysToUtf8(GetUserName(fpgetuid));   //GetUsername in unit Users, fpgetuid in unit BaseUnix
  {$ELSE Linux/BSD}
  Result := GetEnvironmentVariableUtf8('USER');
  {$ENDIF UNIX}
  {$ELSE}
  {$IFDEF WINDOWS}
  Len := MaxLen;
  {$IFnDEF WINCE}
  if Win32MajorVersion <= 4 then
  begin
    SetLength(Result,MaxLen);
    Res := Windows.GetuserName(@Result[1], Len);
    //writeln('GetUserNameA = ',Res);
    if Res then
    begin
      SetLength(Result,Len-1);
      Result := SysToUtf8(Result);
    end
    else SetLength(Result,0);
  end
  else
  {$ENDIF NOT WINCE}
  begin
    SetLength(WS, MaxLen-1);
    Res := Windows.GetUserNameW(@WS[1], Len);
    //writeln('GetUserNameW = ',Res);
    if Res then
    begin
      SetLength(WS, Len - 1);
      Result := Utf16ToUtf8(WS);
    end
    else SetLength(Result,0);
  end;
  {$ENDIF WINDOWS}
  {$ENDIF UNIX}
end;