问题
Hi there i am using delphi FM2 with XE3 in windows 8.
The problem im having is that i want the user to press a button and then navigate to a subfolder located in appdata ex. C:\Users\Kobus\AppData\Roaming.minecraft
Everybody has a diferant username so this wont work.
So i use this code to get the username:
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;
Then i say ShowMessage('C:\Users\'+username+'\AppData\Roaming\.minecraft\saves\');
to check the output.
And the output i get is : 'C:\Users\Kobus' for some reason the rest of the path name is lost.
What i need to be displayed is : 'C:\Users\'Kobus'\AppData\Roaming.minecraft\saves\'
Thanks.
回答1:
The problem is that dwUserNameLen
contains the length of the string, including the trailing zero terminator. So when you do:
SetLength(sUserName, dwUserNameLen);
this results in sUserName
being set to 'Kobus#0'
. At some point you then pass this to a Windows API dialog function that treats the string as a null-terminated string, and truncates the string at the stray null-terminator.
So you fix it like this:
SetLength(sUserName, dwUserNameLen-1);
Note that you should also check the return value of GetUserName
in case that call fails:
if not GetUserName(PChar(sUserName), dwUserNameLen) then
RaiseLastOSError;
or a rather crisper variant:
Win32Check(GetUserName(PChar(sUserName), dwUserNameLen));
One final point. This is the wrong way to get hold of the roaming app data folder. For a start you are assuming all sorts of implementation details. Your approach will fail on older versions of Windows which use different naming patterns. Or some future version of Windows. Or the current versions that have been configured in a different way.
The right way to do this is to ask the system where the roaming app data folder is. Do that using CSIDL_APPDATA
(for older Windows versions), or FOLDERID_RoamingAppData
(for modern Windows versions).
回答2:
I didn't need to dig too long to find a snippet :). So what I use in my own app, after summarising the hints, becomes:
//=================================================================
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
回答3:
i Think your question is one of the XY Problems
Your actual problem that you want to read the full path of %AppData%\.minecraft\saves\
And you thinking in how to read the current Username
Look at CSIDL and SHGetFolderPath
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');
UPDATE
Alternative
Check the GetHomePath function in System.IOUtils
unit.
Will do the same result that you want for multi platforms.
uses System.IOUtils;
procedure TForm17.btn1Click(Sender: TObject);
begin
ShowMessage(TPath.GetHomePath() + TPath.DirectorySeparatorChar + '.minecraft\saves');
end;
回答4:
username := GetEnvironmentVariable('username');
sets username
to the current user's name, obviating the complexity.
来源:https://stackoverflow.com/questions/15555527/how-to-get-the-name-of-the-current-user-in-delphi