Windows FreePascal:如何在非拉丁窗口中使用GetEnvironmentVariable?
我一直在使用Lazarus 1.6.4和FPC 3.0.2编写一些代码,以获取Windows中的用户名和Linux中的用户。为了实现这一点,我使用了SysUtils.GetEnvironmentVariable函数。在Linux中,它工作得很完美,但在Windows中,它返回一些损坏的内容,看起来像是以错误编码打开的UTF8字符串。Windows中的“我的用户名”有西里尔字母符号,因此GetEnvironmentVariable返回的不是实际名称,而是Windows FreePascal:如何在非拉丁窗口中使用GetEnvironmentVariable?,windows,encoding,lazarus,freepascal,Windows,Encoding,Lazarus,Freepascal,我一直在使用Lazarus 1.6.4和FPC 3.0.2编写一些代码,以获取Windows中的用户名和Linux中的用户。为了实现这一点,我使用了SysUtils.GetEnvironmentVariable函数。在Linux中,它工作得很完美,但在Windows中,它返回一些损坏的内容,看起来像是以错误编码打开的UTF8字符串。Windows中的“我的用户名”有西里尔字母符号,因此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;
当其中包含非拉丁符号时,它会返回损坏的字符串
如何在Windows操作系统中以正确的编码获取EnvironmentVariable?经过一天的运行,我找到了适合我的解决方案。您应该使用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;
2017年12月1日更新
正如David在评论中提到的,我的解决方案取决于ENV。在讨论中,我找到了更可靠的解决方案。代码如下:
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;
函数GetCurrentUserName:String;
{$IFDEF WINDOWS}
常数
MaxLen=256;
变量
伦:德沃德;
WS:WideString;
Res:windows.BOOL;
{$ENDIF}
开始
结果:='';
{$IFDEF UNIX}
{$IF(已定义(LINUX))或(已定义(FREEBSD))}
结果:=SYSTOUF8(GetUserName(fpgetuid))//unit Users中的GetUsername,unit BaseUnix中的fpgetuid
{$ELSE Linux/BSD}
结果:=GetEnvironmentVariableUtf8('USER');
{$ENDIF UNIX}
{$ELSE}
{$IFDEF WINDOWS}
Len:=MaxLen;
{$IFnDEF WINCE}
如果3.0+getenvironmentvariable中的Win32MajorVersionAfaik在windows上被重载以进行unicodestring,则使用-W变量
var res,tag : unicodestring;
begin
tag:='HOME';
res:=getenvironmentvariable(tag);
end;
只是
也可能有效,但请确保将utf8设置为默认编码,或将结果分配给Unicode解压。这不是在Windows上获取用户名的方法,而且您不希望在Windows上使用ANSI编码。@DavidFeffernan请详细解释。你有什么建议吗?你永远都不想使用ANSI编码,因为它只能对有限的字符集进行编码。要获取当前用户名,请使用提供该服务的Win32 API函数。例如
GetUserName
。也许Lazarus或FPC RTL已经包装了它,我不知道。@DavidHeffernan Lazarus没有。GetUserName
函数仅在UNIX相关上下文中列出。我不明白,当我的解决方案完成工作并产生正确的输出时,为什么我要使用更复杂的解决方案?显然,你可以随心所欲。但是它不能处理语言环境以外的字符,而且也不能保证环境变量会存在。和GetUserName
将在windows标题翻译中提供。
getenvironmentstring (unicodestring('whatever'));