Solved

Stop a NT Service while it is working

Posted on 2003-12-02
10
474 Views
Last Modified: 2010-04-05
Hello everybody!!!

I made a NT Service with Delphi 5 Enterprise.
This Service, is always waiting for a file and sometimes makes some job that lasts 2 minutes.
If I try to stop the service when it is working, I can't do this. I must wait the end of the job and then, when the service is IDLE, I can press the "Stop" button.

I'd like to have the "stopping" dialog that stills until the job is done and then the service stops regularly.

What can I do?
If I'm not so clear, please, ask me more!!

Roberto
0
Comment
Question by:roburobe
  • 3
  • 3
  • 2
  • +1
10 Comments
 
LVL 10

Expert Comment

by:ADSaunders
ID: 9858438
Hi roburobe,
Don't know about Delphi, But in Any other language including VB, I'd declare a global Boolean (logical) variable (e.g. StopMe) Initially set at false. The 'stop' button Onclick event simply changes the value of this variable to True, and possibly changes displayed text. The server process loop checks the value of this variable at every iteration, and if set to true, gracefully exits.
Point to note: You will have to ensure that events are propagated so that the button click is seen. If the server process is intensive, (IN VB) i'd liberally sprinkle the code with DoEvents statements, there should be something comparable in Delphi.

Regards .. Alan
0
 

Author Comment

by:roburobe
ID: 9858621
Thanks Alan,

I put a global variable called "EndPending" that is checked at the end of each work. If set to true, the whole service stops.

But it still doesn't works!!! In the OnStop Event of the Service, I placed a loop that checks that the job has ended. At the end, I put Stopped to True. Now, the message that says that the service cannot be stopped, appears in less than a second, ignoring my loop!!! How can I tell the Service Control Panel to wait?

Thanks

Roberto
0
 
LVL 10

Expert Comment

by:ADSaunders
ID: 9858774
IN the OnStop event, first set the variable to true, then check for termination. (i.e. reverse what you've done)
That way, the service gets the trigger to stop after the next iteration, and the service manager sees the termination after the wait loop.
0
 

Author Comment

by:roburobe
ID: 9859200
Hello ADSaunders,

Here's my OnStop event:

procedure TAutopostel.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  EndPending := True; // Tell the working job that the user asked to end the service
  Stopped := True;
  While not Ended do // ended is set to true by the working job at the end of the work
                             // and only if endpending is True
  begin
    Sleep(500);
    ReportStatus; // I read it in the help....
  end;
end;

Something's wrong?
0
 
LVL 10

Expert Comment

by:ADSaunders
ID: 9859225
Sorry, I did say I didn't know Delphi. I have used a similar technique in VB before though.

Once again my apologies, maybe someone with some Delphi experience can help.

.. Alan
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 5

Expert Comment

by:snehanshu
ID: 9859391
roburobe,
  I am not sure about this, but does this help (Call ReportStatus before Sleep)?

procedure TAutopostel.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  EndPending := True; // Tell the working job that the user asked to end the service
  Stopped := True;
  While not Ended do // ended is set to true by the working job at the end of the work
                             // and only if endpending is True
  begin
    ReportStatus; // I read it in the help....
    Sleep(500);
  end;
end;

...Shu
0
 
LVL 5

Accepted Solution

by:
snehanshu earned 500 total points
ID: 9863675
roburobe,
>> Now, the message that says that the service cannot be stopped, appears in less than a
>>second, ignoring my loop!!!
  Are you sure that Ended provides you the correct status. I mean, is Ended always "False" when there is some other process going on and does it become true after the processes complete?

To test, you could make your service "interactive", and add a showmessage in the stop code and also tweak it as follows:

procedure TAutopostel.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  EndPending := True; // Tell the working job that the user asked to end the service
  Stopped := False;//Set it to false initially

  ReportStatus; // Report status before the loop also

  If Ended then
    showmessage('Ended is True')
  Else
    showmessage('Ended is False');

  While not Ended do // ended is set to true by the working job at the end of the work
                             // and only if endpending is True
  begin
    ReportStatus; // I read it in the help....
    Sleep(500);
  end;
  Stopped := False;//Set it to True after the while loop
end;
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 9864596
do not use unprotected global variables in services ! each service runs in it's own thread ! (you might have several instances of a service)
first create an event with manual control and defalt to signaled(TEvent class in SyncObjs - dunno if D5 has this .. if not then use CreateEvent API)
when your job starts reset the event and when the job ends set the event
in the OnStop event check for this event: MyEvent.WaitFor(INFINITE) or WaitForSingleObject(hEvent, ...)
the thread that called the Stop method will wait until the job has ended or the timeout period has elapsed
you'll still have to allow your service to get the stop message (DoEvents -vb, Application.ProcessMessages -delphi)
you do this with the following procedure

  {:Process all messages waiting in the current thread's message queue.
    @author  gabr
    @since   2003-08-25
  }        
  procedure DSiProcessThreadMessages;
  var
    msg: TMsg;
  begin
    while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) and (Msg.Message <> WM_QUIT) do begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
  end; { DSiProcessThreadMessages }


you could however stop the job forcefuly also by setting somekind of an event and checking it during processing
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 9864899
ugh ... forget that procedure :) my bad .. you simply call ServiceThread.ProcessRequests(false);
also be careful for deadlocks :)
btw .. that stopping dialog progress can't be stopped .. it periodically checks the service status
you could return the status immediately and notify show a message saying the service is finishing the job .. when done display it's done and stop the service
0
 

Author Comment

by:roburobe
ID: 9865823
snehanshu, you are quite right..... I put some file writing in the ServiceStop method and I see that if I press the "Stop" button in the SCM while the service is doing his job, nothing is written (and the "error" is reported)... at the end of the job, the file is written and the Service taken down.

Probably, the job is very intensive and the software has no time to start the "ServiceStop" event handler.
Now my problem is allow the service to start the ServiceStop Event even if it's working.... Do you have some suggestion?

Thanks

Roberto
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now