First , I want to thank all the persons who works for this site, very useful for a developer. This is the first I am blocked in my developement since 3 days. I have searched solutions on Internet but I find nothing which solves this issue.
So, I develop a service which have to execute an external program on vista/seven/xp when a user is logged. Some characteristics of this service :
To run the external GUI application as the interactive user:
after that, I run the application with this function:
function RunInteractive(prog_filename: String; sessionID: Cardinal): boolean;
var hToken: THandle;
si: _STARTUPINFOA;
pi: _PROCESS_INFORMATION;
begin
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
SI.lpDesktop := nil;
if WTSQueryUserToken(sessionID, hToken)
then begin
if CreateProcessAsUser(hToken, nil, PChar(prog_filename), nil, nil, False, 0, nil, PChar(ExtractFilePath(prog_filename)), si, pi)
then result := true
else result := false;
end
else Begin
result := false;
End;
CloseHandle(hToken);
end;
This code is ok in most of case except one: when I change User. Let me explain it with 2 simple users (Domain\user1 and Domain\user2):
If I do this X times, the result is always the same, very good...but If I do this:
Something is wrong but I don't find the solution. Thanks for your answers...
You don't need to enumerate running explorer.exe processes, you can use WTSGetActiveConsoleSessionId()
instead, and then pass that SessionId to WTSQueryUserToken()
. Note that WTSQueryUserToken()
returns an impersonation token but CreateProcessAsUser()
needs a primary token, so use DuplicateTokenEx()
for that conversion.
You should also use CreateEnvironmentBlock()
so the spawned process has a proper environment that is suited to the user account that is being used.
Lastly, set the STARTUPINFO.lpDesktop
field to 'WinSta0\Default'
instead of nil
so the spawned UI can be made visible correctly.
I have been using this approach for several years now and have not had any problems with it. For example:
function CreateEnvironmentBlock(var lpEnvironment: Pointer; hToken: THandle; bInherit: BOOL): BOOL; stdcall; external 'userenv.dll'
function DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall; external 'userenv.dll';
function RunInteractive(prog_filename: String): Boolean;
var
hUserToken, hToken: THandle;
si: _STARTUPINFOA;
pi: _PROCESS_INFORMATION;
SessionId: DWORD;
Env: Pointer;
begin
Result := False;
ZeroMemory(@si, SizeOf(si));
si.cb := SizeOf(si);
si.lpDesktop := 'WinSta0\Default';
SessionId := WTSGetActiveConsoleSessionId;
if SessionId = $FFFFFFFF then Exit;
if not WTSQueryUserToken(SessionID, hToken) then Exit;
try
if not DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, nil, SecurityIdentification, TokenPrimary, hUserToken) then Exit;
finally
CloseHandle(hToken);
end;
try
if not CreateEnvironmentBlock(Env, hUserToken, False) then Exit;
try
Result := CreateProcessAsUser(hUserToken, nil, PChar(prog_filename), nil, nil, False, CREATE_UNICODE_ENVIRONMENT, Env, PChar(ExtractFilePath(prog_filename)), si, pi);
if Result then
begin
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
end;
finally
DestroyEnvironmentBlock(Env);
end;
finally
CloseHandle(hUserToken);
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With