4

嗨,我在 Windows 8 中使用带有 XE3 的 delphi FM2。

我遇到的问题是我希望用户按下按钮,然后导航到位于 appdata ex 中的子文件夹。C:\Users\Kobus\AppData\Roaming.minecraft

每个人都有不同的用户名,所以这行不通。

所以我使用这段代码来获取用户名:

function GetCurrentUserName : string;
const
  cnMaxUserNameLen = 254;
var
  sUserName     : string;
  dwUserNameLen : DWord;
begin
  dwUserNameLen := cnMaxUserNameLen-1;
  SetLength( sUserName, cnMaxUserNameLen );
  GetUserName(PChar( sUserName ),dwUserNameLen );
  SetLength( sUserName, dwUserNameLen );
  Result := sUserName;
end;

username := GetCurrentUserName;

然后我说ShowMessage('C:\Users\'+username+'\AppData\Roaming\.minecraft\saves\');检查输出。

我得到的输出是:'C:\Users\Kobus' 由于某种原因,路径名的其余部分丢失了。

我需要显示的是:'C:\Users\'Kobus'\AppData\Roaming.minecraft\saves\'

谢谢。

4

4 回答 4

12

问题是dwUserNameLen包含字符串的长度,包括尾随零终止符。所以当你这样做时:

SetLength(sUserName, dwUserNameLen);

这导致sUserName设置为'Kobus#0'。在某些时候,您然后将其传递给 Windows API 对话框函数,该函数将字符串视为以空值结尾的字符串,并在杂散的空值终止符处截断字符串。

所以你像这样修复它:

SetLength(sUserName, dwUserNameLen-1);

请注意,如果GetUserName调用失败,您还应该检查返回值:

if not GetUserName(PChar(sUserName), dwUserNameLen) then
  RaiseLastOSError;

或更清晰的变体:

Win32Check(GetUserName(PChar(sUserName), dwUserNameLen));

最后一点。这是获取漫游应用程序数据文件夹的错误方法。首先,您假设各种实现细节。您的方法将在使用不同命名模式的旧版本 Windows 上失败。或某些未来版本的 Windows。或者以不同方式配置的当前版本。

正确的做法是询问系统漫游应用程序数据文件夹在哪里。使用CSIDL_APPDATA(对于旧 Windows 版本)或FOLDERID_RoamingAppData(对于现代 Windows 版本)执行此操作。

于 2013-03-21T18:41:07.850 回答
1

我不需要挖太久就能找到一个片段:)。所以我在自己的应用程序中使用的东西,在总结了提示之后,变成了:

//=================================================================
procedure TMainF1.UserTestClick(Sender: TObject);
const
  cnMaxUserNameLen = 254;
var
  sUserName     : string;
  dwUserNameLen : DWord;
begin
  dwUserNameLen := cnMaxUserNameLen-1;
  SetLength( sUserName, cnMaxUserNameLen );
  Win32Check(GetUserName( PChar(sUserName), dwUserNameLen ));
  sUserName := PChar( sUserName );
  label_user.Caption := UpperCase(sUserName);
end;

//== works well with D7
于 2014-01-03T13:38:16.927 回答
1

我认为您的问题是XY 问题之一

您想要阅读完整路径的实际问题%AppData%\.minecraft\saves\

而你在思考如何阅读当前Username

看看CSIDLSHGetFolderPath

function GetShellFolder(CSIDLFolder : integer) : string;
begin
  SetLength(Result, MAX_PATH);
  SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, false);
  SetLength(Result, StrLen(PChar(Result)));
  if (Result <> '') then
    Result  := IncludeTrailingBackslash(Result);
end;

....

//Usage
ShowMessage(GetShellFolder(CSIDL_APPDATA)+'.minecraft\saves');

更新

选择

检查单元中的GetHomePath函数System.IOUtils

将为多平台执行您想要的相同结果。

uses System.IOUtils;

procedure TForm17.btn1Click(Sender: TObject);
begin
    ShowMessage(TPath.GetHomePath() + TPath.DirectorySeparatorChar + '.minecraft\saves');
end;
于 2016-01-04T00:40:38.040 回答
-2
username := GetEnvironmentVariable('username');

设置username为当前用户的名称,避免了复杂性。

于 2013-03-21T18:49:22.650 回答