How to get current username in delphi?

Hi, I am using delphi FM2 with XE3 on Windows 8.

The problem is that I want the user to click a button, and then navigate to the subfolder located in appdata ex. C: \ Users \ Cobus \ AppData \ Roaming.minecraft

Everyone has a different username, so this will not 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 will 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.

I need to display the following: 'C: \ Users \' Kobus '\ AppData \ Roaming.minecraft \ saves \'

Thanks.

+4
source share
4 answers

The problem is that dwUserNameLen contains the length of the string, including the terminating null terminator. Therefore, when you do:

 SetLength(sUserName, dwUserNameLen); 

this causes sUserName be set to 'Kobus#0' . At some point, you pass this to the Windows API dialog function, which treats this string as a string with a terminating zero and truncates the string on a random null terminator.

So you fix it like this:

 SetLength(sUserName, dwUserNameLen-1); 

Note that you should also check the return value of GetUserName if the call fails:

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

or a pretty clear option:

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

One last moment. This is the wrong way to get the roaming data folder. For starters, you accept all sorts of implementation details. Your approach will not work on older versions of Windows that use different name patterns. Or in a future version of Windows. Or current versions that were configured differently.

The correct way to do this is to ask the system where the data folder of the roaming application is located. Do this using CSIDL_APPDATA (for older versions of Windows) or FOLDERID_RoamingAppData (for modern versions of Windows).

+12
source

I didn’t have to dig too long to find the fragment :). So, what I use in my application, after summing up the tips, 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 
+1
source

i Think your question is one of the XY issues

Your actual problem you want to read the full path of %AppData%\.minecraft\saves\

And you think how to read the current Username

Take a 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 out GetHomePath in System.IOUtils .

Will do the same result you want for multiple platforms.

 uses System.IOUtils; procedure TForm17.btn1Click(Sender: TObject); begin ShowMessage(TPath.GetHomePath() + TPath.DirectorySeparatorChar + '.minecraft\saves'); end; 
0
source
 username := GetEnvironmentVariable('username'); 

sets username current username, eliminating complexity.

-2
source

All Articles