3

I am using PrivilegesRequired=lowest in my Inno Setup script. If setup is running elevated, i.e. IsAdminLoggedOn or IsPowerUserLoggedOn reports TRUE, how can I determine if the elevated user account is the same account from which setup was launched?

My script can do different things accordingly.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
user3142056
  • 337
  • 2
  • 9

2 Answers2

3

You can use WTSQuerySessionInformation to retrieve an account username for the current Windows logon session.

function WTSQuerySessionInformation(
  hServer: THandle; SessionId: Cardinal; WTSInfoClass: Integer;
  var pBuffer: DWord; var BytesReturned: DWord): Boolean;
  external 'WTSQuerySessionInformationW@wtsapi32.dll stdcall';

procedure WTSFreeMemory(pMemory: DWord);
  external 'WTSFreeMemory@wtsapi32.dll stdcall';

procedure RtlMoveMemoryAsString(Dest: string; Source: DWord; Len: Integer);
  external 'RtlMoveMemory@kernel32.dll stdcall';

const
  WTS_CURRENT_SERVER_HANDLE = 0;
  WTS_CURRENT_SESSION = -1;
  WTSUserName = 5;

function GetCurrentSessionUserName: string;
var
  Buffer: DWord;
  BytesReturned: DWord;
  QueryResult: Boolean;
begin
  QueryResult :=
    WTSQuerySessionInformation(
      WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSUserName, Buffer,
      BytesReturned);

  if not QueryResult then
  begin
    Log('Failed to retrieve username');
    Result := '';
  end
    else
  begin
    SetLength(Result, (BytesReturned div 2) - 1);
    RtlMoveMemoryAsString(Result, Buffer, BytesReturned);
    WTSFreeMemory(Buffer);
    Log(Format('Retrieved username "%s"', [Result]));
  end;
end;

(The code is for Unicode version of Inno Setup – The only version as of Inno Setup 6).


You can then compare the result against GetUserNameString.


You may need to add a domain name into the comparison.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • 1
    The INNO help documentation for GetUserNameString says "Retrieves the name of the user currently logged onto the system." But it's really more like "Retrieves the name of the user for which setup is running." – user3142056 Jan 03 '18 at 14:31
  • 1
    Thanks. For both version support (ansi/unicode): #ifdef UNICODE external 'WTSQuerySessionInformationW@wtsapi32.dll stdcall'; #else external 'WTSQuerySessionInformationA@wtsapi32.dll stdcall'; #endif and: #ifdef UNICODE SetLength(Result, (BytesReturned div 2) - 1); #else SetLength(Result, (BytesReturned) - 1); #endif – carlos Aug 29 '18 at 17:51
  • 1
    @carlos Thanks for sharing this. Though everyone should really use Unicode version. – Martin Prikryl Aug 30 '18 at 05:50
0

If you need the full account name of the current user (e.g., authority\username format), you can use the GetUserNameExW Windows API function. The below snippet demonstrates how to call this function from Inno Setup:

const
  ERROR_MORE_DATA = 234;

function GetUserNameExW(NameFormat: Integer; lpNameBuffer: string; var nSize: DWORD): Boolean;
  external 'GetUserNameExW@secur32.dll stdcall';

function GetFullUserName(): string;
var
  NumChars: DWORD;
  OutStr: string;
begin
  result := '';
  NumChars := 0;
  if (not GetUserNameExW(2, '', NumChars)) and (DLLGetLastError() = ERROR_MORE_DATA) then
  begin
    SetLength(OutStr, NumChars);
    if GetUserNameExW(2, OutStr, NumChars) then
      result := Copy(OutStr, 1, NumChars);
  end;
end;

(The value 2 passed to the first parameter (NameFormat) in the GetUserNameExW function corresponds to NameSamCompatible in the EXTENDED_NAME_FORMAT enumeration.)

Bill_Stewart
  • 22,916
  • 4
  • 51
  • 62