Задать вопрос

Как в Delphi запустить процесса из сервиса?

Здравствуйте. Имеется сервис на Delphi, который должен запускать внешнюю программу. Используется функция ShellExecute. После вызова функции процесс запускается, но занимает очень мало памяти и GUI приложения не показывается. Пробовал запускать batch файл, в процессах зависал cmd.exe. Я думаю что причина моих бед - запуск приложений под системным пользователем, который наверное и не даёт ему показывать окно. В аналогичной теме на Тостере уже был, но рабочее решение там отсутствовало.

Итак вопрос: как запустить приложение под текущем пользователем(пользователем, на котором сейчас открыт десктоп) из сервиса.

Windows 7 x64, Delphi 7, Залогинен под админом, "Разрешить взаимодействие с рабочим столом" стоит

P.S. Поиск использовал.
  • Вопрос задан
  • 5662 просмотра
Подписаться 6 Оценить Комментировать
Решения вопроса 1
@terminator48 Автор вопроса
Ладно, всем спасибо за ответы, но я сам уже нашёл решение:

uses JwaWindows, JwsclToken, JwsclSid, JwsclStrings
procedure RunApp(str: string);
var
  UserToken : TJwSecurityToken;
  ConsoleUser : TJwSecurityId;
  UserSidString,
  UserName : TJwString;
struc1: LPSTARTUPINFO;
struc2: PROCESS_INFORMATION;
begin

getmem(struc1, sizeof(TSTARTUPINFO));

struc1^.lpDesktop := PChar('winsta0\default');
struc1^.dwFlags := STARTF_USESHOWWINDOW;
struc1^.wShowWindow := SW_SHOW;
  UserToken := TJwSecurityToken.CreateWTSQueryUserToken(WTS_CURRENT_SESSION);
  CreateProcessAsUser(UserToken.TokenHandle, nil,
      PChar(str+' 1000'),
       nil, nil, false, Create_default_error_mode, nil, nil, struc1^, struc2);
    UserToken.RevertToSelf;
  FreeAndNil(UserToken);
end;
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
MaxiMonster
@MaxiMonster
Здравствуйте. Погуглил для вас и нашел такой вариант решения:

procedure RunApp(str: pchar);
var
struc1: PSTARTUPINFO;
struc2: PROCESS_INFORMATION;
begin

getmem(struc1, sizeof(TSTARTUPINFO));

struc1^.lpDesktop := PChar('winsta0\default');
struc1^.dwFlags := STARTF_USESHOWWINDOW;
struc1^.wShowWindow := SW_SHOW;

CreateProcess(nil, str, nil, nil, False,
NORMAL_PRIORITY_CLASS,
nil, nil, struc1^, struc2);

end;

Помогает, но будут утечки памяти.

Майкрософт говорит использовать в вашем случае такие функции:
CreateProcessWithLogonW
CreateProcessAsUser
Ответ написан
fart
@fart
Реализуйте приложение запущенное в сессии пользователя, которое слушает порт или pipe. Сервис будет "общаться" с пользователем через это приложение. Конечно, есть минусы этой реализации, но работает везде. Мне приходилось так делать когда служба была написана на C#.
Ответ написан
@s0m
100% рабочий код. Сам сервис запускается из-под конкретного пользователя.
В противном случае нужно эти права получать програмным путём.

TServ = class(TService)
        procedure ServiceStart(Sender: TService; var Started: Boolean);
	procedure ServiceExecute(Sender: TService);
	procedure ServiceCreate(Sender: TObject);
  public
	function GetServiceController: TServiceController; override;
  end;

procedure TServ.ServiceExecute(Sender: TService);
var
	si : TStartupInfo;
	pi : TProcessInformation;
begin
	FillMemory( @pi, SizeOf( pi ), 0 );
	GetStartupInfo( si );

	CreateProcess(PAnsiChar(exe), PAnsiChar(params), nil, nil, false, 0, nil, PAnsiChar(dir), si, pi );
	CloseHandle(pi.hThread);

	while not Terminated do begin
		ServiceThread. ProcessRequests( False );
		Sleep(250);
	end;

	TerminateProcess(pi.hProcess, 1);
end;
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы