views:

280

answers:

2

Hi, I am new to Writing Windows Service apps and having problems.

Written in Delphi, I have written a normal windows application to check and debug the major parts of the code and now have to convert it to an NT Service.

My code has to launch a windows application which I do using the following code.

function Run_Program : boolean;
   var SEInfo : TShellExecuteInfo;
   ExitCode : DWORD;
   begin
     Result := false;
     FillChar(SEInfo, SizeOf(SEInfo),0);
     SEInfo.cbSize :=SizeOf(TShellExecuteInfo);
     With SEInfo do
     begin
       fMask := SEE_MASK_NOCLOSEPROCESS;
       Wnd := **Application.Handle**;
       lpFile := PChar(Exe_Prog);
       lpParameters := PChar(Exe_Param);
       nShow := SW_SHOWNORMAL;
     end;
     If ShellExecuteEx(@SEInfo) then
     begin
       repeat
         Application.ProcessMessages;
         GetExitCodeProcess(SEInfo.hProcess, ExitCode);
       until (ExitCode <> STILL_ACTIVE) OR Application.Terminated OR NOT q1.fieldbyName('Delay').AsBoolean;
       If ExitCode <> STILL_ACTIVE then Record_Event(Exe_Prog + ' completed ') else
          Record_Event(Exe_Prog + ' activated ');
       Result := true;
     end
     else Record_Event('Error Starting '+ Exe_Prog+ ' ');
  end;

When this is put in the service app the compiler fails with 3 errors: Undeclared identifiers.. 1) Handle 2) ProcessMessages and 3) Terminated.

My question is.. are there equivalent procedures that can be used in a service application or should I approach the problem differently in a service application?

Any help would be appreciated

+3  A: 

Don't use ShellExecute() to launch a .exe file. This is especially important in services, which do not run within the Shell to begin with. Use CreateProcess() for that (on Vista and later, use CreateProcesAsUser() instead).

Use ServiceThread.ProcessRequests() and ServiceThread.Terminated instead of Application.ProcessMessages() and Application.Terminated.

Remy Lebeau - TeamB
+1  A: 

Be aware that running applications from a service in Vista and 7 may not work as expected. Services in Vista and 7 are run in a different windows station which is not visible to the logged on user.

Also be aware that if an application is executed by a service, it runs with the service user privilege - it should be run using CreateProcessAsUser() to avoid to run an application with very elevated privileges (i.e. LocalSystem, unless that is the reason), because it can expose the system to big security risks.

If you need to check if an application exits there is no need to wait in a loop like that. Use WaitForSingleObject() on a separate thread. It won't swallow all those CPU cycles, Windows itself will signal the exit in a polite manner.

The service main thread should simply listen for Service Control Manager commands. Delphi allows to use ProcessRequests() to process those calls when using the main thread for actual processing, but it is better to follow the documentation and use a separate thread for processing.

ldsandon
+1, all *very* good points.
mghie