Reputation: 781
My process (regular app, not a service. app is launched by service, not by user, but in user's session) runs under SYSTEM account (it's required by other reasons) in user's session(s). Is there any way to get current session's user friendly name if the PC is in a workgroup?
-getting desktop's ('Progrman') user as -GetTokenInformation - LookupAccountSid - and making a TranslateName does not give me the f.name () in a workgroup (as written in msdn, it works in a domain).
-GetUserNameExW does not give me f.name because my process works under SYSTEM account (GetUserNameExW retrieves the data for calling process's account)
So, is there any other way of process-independent user friendly name providing for workgroups ?
function GetUserNameEx(var AUserName: string; var AFriendlyUserName: string): Boolean;
var
ProcessID: Integer;
phToken, hProcess, hWindow: THandle;
cbBuf: Cardinal;
ptiUser: PTOKEN_USER;
snu: SID_NAME_USE;
szDomain, szUser : array [0..50] of Char;
chDomain, chUser : Cardinal;
UserName1: array[0..250] of Char;
FriendlyUserName: array[0..250] of Char;
Size: DWORD;
const
NameUnknown = 0; // Unknown name type.
NameFullyQualifiedDN = 1; // Fully qualified distinguished name
NameSamCompatible = 2; // Windows NT® 4.0 account name
NameDisplay = 3; // A "friendly" display name
NameUniqueId = 6; // GUID string that the IIDFromString function returns
NameCanonical = 7; // Complete canonical name
NameUserPrincipal = 8; // User principal name
NameCanonicalEx = 9;
NameServicePrincipal = 10; // Generalized service principal name
DNSDomainName = 11; // DNS domain name, plus the user name
begin
Result := False;
AUserName := '';
AFriendlyUserName := '';
hWindow := FindWindow('Progman', 'Program Manager');
if hWindow <> 0 then
begin
GetWindowThreadProcessID(hWindow, @ProcessID);
hProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
if hProcess <> 0 then
begin
if OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, phToken) then
begin
if not GetTokenInformation(phToken, TokenUser, nil, 0, cbBuf) then
if GetLastError()<> ERROR_INSUFFICIENT_BUFFER then exit;
if cbBuf = 0 then exit;
GetMem(ptiUser, cbBuf);
try
chDomain := 50;
chUser := 50;
if GetTokenInformation(phToken, TokenUser, ptiUser, cbBuf, cbBuf) then
if LookupAccountSid(nil, ptiUser.User.Sid, szUser, chUser, szDomain,
chDomain, snu) then
begin
AUserName := szUser;
Result := True;
if Trim(szDomain) <> '' then
begin
FillChar(UserName1, 251, 0);
FillChar(FriendlyUserName, 251, 0);
StrCopy(UserName1, PChar(Trim(szDomain) + '\' + Trim(szUser)));
Size := 251;
//THIS CODE WORKS FOR DOMAINS ONLY, NOT FOR WORKGROUPS
if TranslateName(@UserName1, NameSamCompatible, NameDisplay, @FriendlyUserName, @Size) then
AFriendlyUserName := Trim(FriendlyUserName);
end;
end
else
raise Exception.Create('Error in GetTokenUser');
finally
FreeMem(ptiUser);
end;
end
else begin
AUserName := 'OpenProcessToken = False';
Result := False;
end
end
else begin
AUserName := '';
Result := False;
end
end
else begin
AUserName := '';
Result := False;
end
end;
Upvotes: 0
Views: 417
Reputation: 101764
GetUserNameEx
respects impersonation so you can call ImpersonateLoggedOnUser
with your token to get information about the user.
However, in a workgroup environment only NameSamCompatible
seems to work and everything else returns ERROR_NONE_MAPPED (The user name is not available in the specified format).
Calling NetUserGetInfo
also just returns a empty string for usri*_full_name
.
There is also a undocumented shell function to retrieve the display name but it just falls back to GetUserName
when GetUserNameEx
fails.
Upvotes: 1