procedure ProgramExecute(
var PW1, PW2, PW3 :
string);
var
SI : TStartupInfo;
PI : TProcessInformation;
CmdLine :
String;
ProcCreated : Boolean;
hUserToken : THandle;
ActiveSessionID : Integer;
hShell : THandle;
hToken : THandle;
pEnv : Pointer;
ServiceToken, CopiedToken, UserToken : TJwSecurityToken;
begin
if IsWtsAvailable
then // usually XP and Vista.
begin
ActiveSessionID := GetActiveWtsSession;
if ActiveSessionID < 0
then
begin
ShowMessage('
GetActiveWtsSession returned -1, no user logged on');
Exit;
end;
// { Show MessageBox, this is blocking, prevents service from answering }
// { control messages from SCM, Timeout in seconds ! }
// f_WtsSendMessage(WTS_CURRENT_SERVER_HANDLE, ActiveSessionID,
// PChar(Title), Length(Title) + 1, PChar(Msg), Length(Msg) + 1,
// MB_YESNO or MB_ICONQUESTION, 30, MsgResult, TRUE);
// if MsgResult <> IDYES then
// Exit;
{ Get the user token from WtsApi }
if not f_WTSQueryUserToken(ActiveSessionID, hUserToken)
then
begin
AppendStringToFile(('
WTSQueryUserToken error ' + SysErrorMessage(GetLastError)), Dateiname);
Exit;
end;
end
else begin // usually NT and W2K.
if (Win32Platform = VER_PLATFORM_WIN32_NT)
and
(Win32MajorVersion >= 6)
then
begin
{ Will most likely never happen }
//AppendStringToFile(('Can''t display a message box in Vista if Wts isn''t ' +
// 'available'), Dateiname);
//Exit;
end;
{ Requires PSAPI.DLL which isn't available in all NT4-Versions, }
{ however it's a distributable! }
hShell := GetShellHandle;
if hShell = 0
then
begin
AppendStringToFile(('
No shell handle, no user logged on or PsApi not available'), Dateiname);
Exit;
end;
try
// { Show MessageBox, this is blocking, prevents service from }
// { answering control messages from SCM. }
// if MessageBox(0, PChar(Msg), PChar(Title),
// MB_SERVICE_NOTIFICATION or MB_YESNO or
// MB_ICONQUESTION) <> IDYES then
// Exit;
{ Get the user token from the shell process }
if not OpenProcessToken(hShell, TOKEN_ALL_ACCESS, hUserToken)
then
begin
AppendStringToFile('
OpenProcessToken error ' + SysErrorMessage(GetLastError), Dateiname);
Exit;
end;
finally
CloseHandle(hShell);
end;
end;
//get the token from the service system session
ServiceToken := TJwSecurityToken.CreateTokenEffective(MAXIMUM_ALLOWED);
//copy the token to be able to change the TokenSessionId
//Info: Win2000: Only 0
// WinXP: Service=0, 1.User=0, 2.User=1, 3.User=2, ...
// WinVista: Service=0, 1.User=1, 2.User=2, 3.User=3, ...
CopiedToken := TJwSecurityToken.CreateDuplicateExistingToken(ServiceToken.TokenHandle, MAXIMUM_ALLOWED);
//get the token of the logged in user
if GetWinVersion = wvWin2000
then
UserToken := TJwSecurityToken.CreateCompatibilityQueryUserToken(MAXIMUM_ALLOWED, '
explorer.exe')
else //XP, 2003, Vista, 2008
UserToken := TJwSecurityToken.CreateWTSQueryUserTokenEx(
nil, WtsGetActiveConsoleSessionID);
//give the copied token the same sessionid as the logged in user
CopiedToken.TokenSessionId := UserToken.TokenSessionId;
//create the environment block using the logged in user
if not WTSQueryUserToken(WTSGetActiveConsoleSessionId, hToken)
then
RaiseLastOSError;
JwaWindows.CreateEnvironmentBlock(@pEnv, UserToken.TokenHandle, true);
try
CmdLine := Format('
"%s%s" %s',[IncludeTrailingPathDelimiter(PW1),PW2,PW3]);
FillChar(SI, SizeOf(SI), #0);
FillChar(PI, SizeOf(PI), #0);
SI.cb := SizeOf(SI);
SI.lpDesktop := PChar('
Winsta0\Default');
SI.dwFlags := STARTF_USESHOWWINDOW;
SI.wShowWindow := SW_SHOWDEFAULT;
ProcCreated := CreateProcessAsUser(
hUserToken,
nil,
PChar(CmdLine),
// pointer to command line string
nil,
// pointer to process security attributes
nil,
// pointer to thread security attributes
True,
// handle inheritance
CREATE_NEW_CONSOLE
or CREATE_DEFAULT_ERROR_MODE
or CREATE_UNICODE_ENVIRONMENT,
// creation flags
pEnv,
// pointer to new environment block
nil,
// pointer to current directory name
SI,
// STARTUPINFO
PI);
// PROCESS_INFORMATION
if ProcCreated
then
begin
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
DestroyEnvironmentBlock(pEnv);
end
else
AppendStringToFile('
Error ' + SysErrorMessage(GetLastError), Dateiname);
finally
CloseHandle(hUserToken);
end;
end;