T
T
terminator482014-02-11 17:15:55
Delphi
terminator48, 2014-02-11 17:15:55

How to start a process from a service in Delphi?

Hello. There is a Delphi service that should run an external program. The ShellExecute function is used. After the function is called, the process starts, but takes up very little memory and the application's GUI is not shown. I tried to run a batch file, cmd.exe was hanging in the processes. I think that the reason for my troubles is running applications under the system user, which probably does not allow him to show the window. I already had a similar topic on the Toaster, but there was no working solution there.
So the question is: how to run the application under the current user (the user on which the desktop is currently open) from the service.
Windows 7 x64, Delphi 7, Logged in as admin, "Allow interaction with the desktop" is worth
PS Search used.

Answer the question

In order to leave comments, you need to log in

4 answer(s)
T
terminator48, 2014-02-13
@terminator48

Okay, thanks everyone for the answers, but I already found the solution myself:
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;

O
Oleg, 2014-02-11
@MaxiMonster

Hello. Googled for you and found this solution:
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;
Helps, but there will be memory leaks.
Microsoft says to use the following functions in your case:
CreateProcessWithLogonW
CreateProcessAsUser

F
fart, 2014-02-11
@fart

Implement an application running in a user session that listens on a port or pipe. The service will "communicate" with the user through this application. Of course, there are downsides to this implementation, but it works everywhere. I had to do this when the service was written in C#.

S
s0m, 2014-02-12
@s0m

100% working code. The service itself is launched under a specific user.
Otherwise, you need to get these rights programmatically.

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;

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question