Thanx to Kate Gregory for help.
There is a working code on Delphi:
function RunAsUser(CommandLine, WorkDirectory: string; Wait: Boolean): Boolean;
const
TOKEN_ADJUST_SESSIONID = $0100;
dwTokenRights = TOKEN_QUERY or TOKEN_ASSIGN_PRIMARY or TOKEN_DUPLICATE or TOKEN_ADJUST_DEFAULT or TOKEN_ADJUST_SESSIONID;
var
WExe, WCmdLine, wCurrDir: WideString;
hProcessToken, dwLastErr, retLength, hwnd, dwPID, hShellProcess, hShellProcessToken, hPrimaryToken: Cardinal;
tkp: TOKEN_PRIVILEGES;
PI: TProcessInformation;
SI: TStartupInfoW;
begin
Result:= False;
hShellProcessToken:= 0;
hPrimaryToken:= 0;
hShellProcess:= 0;
if WorkDirectory = '' then WorkDirectory:= GetCurrentDir;
Wexe:= SeparateText(CommandLine, ' ');
WCmdLine:= CommandLine;
wCurrDir:= WorkDirectory;
// Enable SeIncreaseQuotaPrivilege in this process. (This won't work if current process is not elevated.)
if not OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hProcessToken) then Exit;
tkp.PrivilegeCount:= 1;
LookupPrivilegeValueW(nil, SE_INCREASE_QUOTA_NAME, tkp.Privileges[0].Luid);
tkp.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hProcessToken, FALSE, tkp, 0, nil, retLength);
dwLastErr:= GetLastError();
CloseHandle(hProcessToken);
if (dwLastErr <> ERROR_SUCCESS) then Exit;
// Get an HWND representing the desktop shell.
// CAVEATS: This will fail if the shell is not running (crashed or terminated), or the default shell has been
// replaced with a custom shell. This also won't return what you probably want if Explorer has been terminated and
// restarted elevated.
hwnd:= GetShellWindow();
if hwnd = 0 then Exit;
// Get the PID of the desktop shell process.
GetWindowThreadProcessId(hwnd, dwPID);
if dwPID = 0 then Exit;
// Open the desktop shell process in order to query it (get the token)
hShellProcess:= OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID);
if hShellProcess = 0 then Exit;
// From this point down, we have handles to close, so make sure to clean up.
try
// Get the process token of the desktop shell.
if not OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken) then Exit;
// Duplicate the shell's process token to get a primary token.
// Based on experimentation, this is the minimal set of rights required for CreateProcessWithTokenW (contrary to current documentation).
if not DuplicateTokenEx(hShellProcessToken, dwTokenRights, nil, SecurityImpersonation, TokenPrimary, hPrimaryToken) then Exit;
SI.cb:= SizeOf(SI);
FillChar(SI, SI.cb, 0);
SI.wShowWindow:= SW_SHOWNORMAL;
SI.dwFlags:= STARTF_USESHOWWINDOW;
// Start the target process with the new token.
Result:= CreateProcessWithTokenW(
hPrimaryToken,
0,
PWideChar(WExe),
PWideChar(wCmdLine),
0,
nil,
PWideChar(wCurrDir),
@si,
@pi);
if not Result then Exit;
if Wait then
while MsgWaitForMultipleObjects(1, PI.hProcess, False, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0 do
ProcessMessages;
CloseHandle(PI.hProcess);
finally
// Clean up resources
CloseHandle(hShellProcessToken);
CloseHandle(hPrimaryToken);
CloseHandle(hShellProcess);
end;
end;