-2

I wish to retrieve the username of the currently logged in user in Windows (preferably some solution that works from Windows XP to W10) in a Delphi 7 project.

I tried both solutions given in this question, but they all give the name of the user, not the actual "username" that is used to log into Windows.

For example, the "username" I use to log into Windows is "joao.victor" (using a local Windows account), or my e-mail when I use a Microsoft account. But when I tried those 2 solutions, the string it returned was "João", which is my first name and the name configured in those accounts.

Does anyone know of a solution where I can retrieve the username that is used to log into Windows instead of the first name of the user?

  • `GetUserName` returns the login account name, not the user's human name. Also look at `GetUserNameEx`, which gives you more control over the format of the output. – Remy Lebeau Jul 04 '17 at 18:48
  • [NameUserPrincipal](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724268(v=vs.85).aspx) maybe ([this one](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380525(v=vs.85).aspx#user_principal_name))? – Victoria Jul 04 '17 at 18:50
  • 2
    Do you want the username for the account your application is running as, or the account that is logged onto the current session? What does the `whoami` command (run from a command window) say your username is? – Harry Johnston Jul 04 '17 at 23:35
  • @HarryJohnston good point about the process user being different than the session user. In the latter case, you could use [`WTSQuerySessionInformation()`](https://msdn.microsoft.com/en-us/library/aa383838.aspx) – Remy Lebeau Jul 05 '17 at 02:52
  • @HarryJohnston "whoami" resulted in "C-034\João". C-034 is the name of the computer I'm using. I use "joao.victor" to log into Windows, not "João". – João Victor Oliveira Jul 05 '17 at 12:55
  • @RemyLebeau GetUserName returns "João", but I took a look at GetUserNameEx and it seems "NameUserPrincipal" would return what I want, but I can't make it work. It always return an empty string. – João Victor Oliveira Jul 05 '17 at 13:32
  • @Victoria Tried your suggestion of using NameUserPrincipal as parameter of GetUserNameEx, but I can't make it work. – João Victor Oliveira Jul 05 '17 at 13:34
  • 1
    "whoami", without any additional switch, returns the currently logged on user's user name. You may be trying to retrieve something else but there's no point in disputing what your user name is with the OS. – Sertac Akyuz Jul 05 '17 at 18:52
  • @SertacAkyuz Alright, then. The only mystery remaining is why I use "joao.victor" to login. – João Victor Oliveira Jul 05 '17 at 19:00
  • 1
    Perhaps that is an alias for your Microsoft Account? I'm still confused about how the whole "cloud logon" thing actually works, but I do know it means that you don't necessarily use your actual username when logging in. – Harry Johnston Jul 05 '17 at 21:21

5 Answers5

0

Have you tried this?

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(GetCurrentUserName);
end;

function TForm1.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;

or alternatively

function UserName: String;
var User: PChar;
    i: DWord;
begin
  i := 1024;
  user := StrAlloc(Succ(i));
  if GetUserName(User, i) then 
     Result := StrPas(User)
  else 
     Result := 'unknown';
end;

These 2 functions return the username you see on Windows login

See GetUserName

Alec
  • 569
  • 2
  • 17
  • 27
  • This is one of the solutions provided in the question I linked, and it brings me "João" instead of "joao.victor". Same as "GetEnvironmentVariable('USERNAME')". – João Victor Oliveira Jul 05 '17 at 12:51
0

GetUserNameEx is the most flexible, and offers various user names depending on the context and format you're looking to obtain. I don't know if it works in XP, but it does in Windows 2000 and up (tested up to Windows 7, Server 2008 and Windows Server 2012).

Here's a sample console app that has some type definitions that will help, along with the function declaration and sample code that demonstrates the possibilities. It compiles in both D2007 and Seattle/Berlin.

program Project1;

{$APPTYPE CONSOLE}

uses
  System.SysUtils, WinAPI.Windows;

type
  EXTENDED_NAME_FORMAT = DWORD;

const
  NameUnknown           = 0;
  NameFullyQualifiedDN  = 1;
  NameSamCompatible     = 2;  
  NameDisplay           = 3;  
  NameUniqueId          = 6;
  NameCanonical         = 7;
  NameUserPrincipal     = 8;
  NameCanonicalEx       = 9;
  NameServicePrincipal  = 10;
  NameDnsDomain         = 12;


const
  NameFormats: array[0..8] of EXTENDED_NAME_FORMAT = (NameFullyQualifiedDN,
                                                      NameSamCompatible,
                                                      NameDisplay,
                                                      NameUniqueID,
                                                      NameCanonical,
                                                      NameUserPrincipal,
                                                      NameCanonicalEx,
                                                      NameServicePrincipal,
                                                      NameDnsDomain);

function GetUserNameExW(NameFormat: EXTENDED_NAME_FORMAT; lpNameBuffer: LPWSTR;
  var nSize: ULONG): BOOL; stdcall; 
    external 'secur32.dll' Name 'GetUserNameExW';

var
  UserName: String;
  Size: ULONG;
  i: Integer;
begin
  for i := Low(NameFormats) to High(NameFormats) do
  begin
    Size := 0;
    GetUserNameExW(NameFormats[i], nil, Size);
    SetLength(UserName, Size);
    if GetUserNameExW(NameFormats[i], PWideChar(UserName), Size) then
      WriteLn(Ord(NameFormats[i]), #32 + UserName);
  end;
  ReadLn;
end.
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • Well done (I'm not sure which name format OP looks for as well, hence my initial guess), though I would check the first `GetUserNameExW` function call error for `ERROR_MORE_DATA` because there can be other reasons of failure (sort of `if not GetUserNameExW(NameFormats[i], nil, Size) and (GetLastError = ERROR_MORE_DATA) then ` or store the `GetLastError` and print it out by `SysErrorMessage` with the used `NameFormats` index). – Victoria Jul 05 '17 at 21:56
  • @Victoria: There are only two additional reasons for failure. The first is `ERROR_NOT_MAPPED`, which is not possible if you only use the types I put in the `NameFormats` array, and `ERROR_NO_DOMAIN`, which means you're not on a domain login; there's not much point in using this instead of GetUserName if you're not on a domain. But yes, in production code running on various OSes you'd be absolutely correct. – Ken White Jul 05 '17 at 21:56
  • I see your post (to choose which format OP actually wants; upvoted already). I meant, that there's no reason to allocate buffer for another call that naturally fails for the same reason (and reporting why you cannot use certain format might be handsome). – Victoria Jul 05 '17 at 22:02
  • 3
    @Victoria: Yes, I've already agreed with what you said. :-) The best solution would be to add all the appropriate checking of values. I didn't offer to write a fully functional wrapper; I demonstrated using the function and the various outputs it provides. I leave full error checking to the person using the code to implement in their code. – Ken White Jul 05 '17 at 22:05
-1

Short answer: use wmic. Long answer check my answer at https://stackoverflow.com/a/58377194/3584693

Deepak
  • 3,648
  • 1
  • 22
  • 17
-2

With LUA and RunAs and whatnot this is far more complicated than it seems.. But the oldest and simplest trick still works even when switching accounts.

in pre Server 2003 use:

 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersioin\Winlogon DefaultUserName

and above:

 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI LastLoggedOnSAMUser

LastLoggedOnSAMUser will be in format DOMAIN\USERNAME where a local domain can be a Period.

FredS
  • 680
  • 1
  • 5
  • 6
  • "The last person to log into the computer" and "the person logged into the current session" aren't necessarily the same thing. This probably works OK most of the time for an interactive application running on an unmodified desktop build of Windows, but it is kind of fragile. – Harry Johnston Jul 05 '17 at 01:01
  • @Harry, exactly what I thought. By the time I reached that old code I had already coded all the other methods, yet even after spending well over an hour attempting to break it I couldn't.. – FredS Jul 05 '17 at 01:45
-3

i don't have windows XP to test it but i tried it on delphi 7 and delphi 10 Seattle

ShowMessage(GetEnvironmentVariable('USERNAME'));
Someone
  • 401
  • 3
  • 5
  • 16