Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 276
  • Last Modified:

novice Service writer

i'm new at writing services. i've written my first one in D7 that attempts to update a field in a table when a someone alters the clock on the computer, but am having trouble running/connecting it to the time change event (so it seems). i'm attaching my .pas file (in a text document), in hopes someone can tell me what's missing from the code. i think i may be missing a component or two but i'm not sure. the file compiles fine and i can install the service but when i start it and make a change to the time it doesn't do anything. it seems like its just running but not watching/listening for the time change.
ServicePas.txt
0
Michael Sterling
Asked:
Michael Sterling
  • 9
  • 5
  • 5
  • +1
2 Solutions
 
JohnjcesCommented:
What code do you have in your timer procedure?

You need to put code in there that every 10 seconds the timer fires, checks to see if the time has changed greater or less than 10 seconds, then write to the database and do whatever in your log.

John
0
 
JohnjcesCommented:
I am however not certain why your windows message is not firing in your service. Works in regular win 32 apps....

So, I am at a loss...

john
0
 
JohnjcesCommented:
A question,

is your service set to interact with the desktop?
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Michael SterlingWeb Applications DeveloperAuthor Commented:
no its not set to interact with the desktop. is that the problem?
0
 
JohnjcesCommented:
I am not certain, but it is simple to try it. In this manner you may be able to get a messagebox on success/failure as I recall.

John
0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
i think i need to make/declare the service as a system process maybe. how do i do that?
0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
also,..on a different but related note,...from a dos window when i installed my service,...i ran:

myService.exe /install

when i look it up in the SCM the name of it is: "Service 1" how do i fix this and give it a better name?
0
 
SteveBayCommented:
Change the Display Name in the properties of the TService.
0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
that worked (the name change), but my service seems to still not be working once i start it. i'm attaching the new code. i did enable that timer (disabled then enabled). originally enabled in the execute.
ServicePas.txt
0
 
SteveBayCommented:
Per John's first suggestion you could do something like this and detect a time change greater than a second. Also this avoids using windows messaging which will not work in Vista anyway.
procedure TSystemSetBack.Timer1Timer(Sender: TObject);
var
  TheTime: TDateTime;
begin
     Timer1.Enabled := False;
     try
     TheTime := Now;
 
     if ((FLastTime + OneSecond) > (TheTime - (Timer1.Interval * OneMillisecond))) and
        (FLastTime < (TheTime - (Timer1.Interval * OneMillisecond) )) then
          FTimeChanged := False
     else
          FTimeChanged := True;
 
     if FTimeChanged then
          begin
          upDateNow.Close;
          upDateNow.Parameters.ParamByName( 'tmNw' ).Value := TheTime;
          upDateNow.Prepared := True;
          upDateNow.ExecSQL;
          end;
     end;
     FLastTime := TheTime;
     except
     end;
     LogData('Hello');
     Timer1.Enabled := True;
end;

Open in new window

0
 
SteveBayCommented:
Note: Add DateUtils to your uses clause
0
 
JohnjcesCommented:
Ahh, are you using Vista? That will certainly make some differences!

John
0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
i'm not currently using vista. i'd be more than willing to use that code in my timer. i still don't think my service is being "recognized" or being connected properly. i can see it in the SCM window as "Started" but no matter what i do to the clock it doesn't do anything. I do have it set to interact with the desktop.
0
 
SteveBayCommented:
Slight error in the if statement:
     if ((FLastTime + OneSecond) > (TheTime - (Timer1.Interval * OneMillisecond))) and
        (FLastTime < (TheTime - (Timer1.Interval * OneMillisecond) + OneSecond ) ) then

Open in new window

0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
and...i can IncSecond(FLastTime, 1) to add a second  but how do i multiply by one millisecond???
0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
nevermind that last question...i didn't know it was a constant in delphi...
0
 
SteveBayCommented:
Try this code. I put in a service app and tested it. It works for me.
procedure TSystemSetBack.Timer1Timer(Sender: TObject);
var  TheTime: TDateTime;
     LogFile : String;
     LogList : TStringList;
begin
     Timer1.Enabled := False;
     try
     TheTime := Now;
 
     if ((FLastTime + OneSecond) > (TheTime - (Timer1.Interval * OneMillisecond))) and
        (FLastTime < (TheTime - (Timer1.Interval * OneMillisecond) + OneSecond ) ) then
          FTimeChanged := False
     else
          FTimeChanged := True;
 
     if FTimeChanged then
          begin
          LogList := TStringList.Create;
          LogFile := ChangeFileExt(ParamStr(0),'.log');
          if FileExists(LogFile) then
               LogList.LoadFromFile(LogFile);
          LogList.Add(Format('LastTime: %s <> NewTime: %s', [DateTimeToStr(FLastTime), DateTimeToStr(TheTime)]));
          LogList.SaveToFile(LogFile);
          LogList.Free;
          end;
     FLastTime := TheTime;
     except
     end;
     Timer1.Enabled := True;
end;

Open in new window

0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
i'm not sure what i did but the code that Seve gave me worked when i opened/started a new service app. so i awarde him most of the points. i gave john the remainder as i didn't know that i needed to set that property. thanks to all for your time (patience) and efforts...
0
 
TheRealLokiSenior DeveloperCommented:
Firstly, you are missing 1 very important part...

procedure TService1.ServiceExecute(Sender: TService);
begin
  while not self.Terminated do
    self.ServiceThread.ProcessRequests(true);
end;

Secondly, I don't think services can easily receive windows messages

Thirdly, you should probably be using a thread instead of a TTimer, but if it works, go for it :-)
0
 
Michael SterlingWeb Applications DeveloperAuthor Commented:
TheRealLoki: Thanks for that code suggestionsI will implement that code. It seems to take (be able to pickup/listen to )the time change event pretty well. I'm curious about your thread suggestion and would be open to try it if there were some examples. I'm more of a novice to using / coding threads so I'd need some guidance. I'm open to continue this discussion if you are...
0
 
TheRealLokiSenior DeveloperCommented:
receiving broadcast messages when your serviceis set to interactive does not seem to be a problem. but if it were a specific message, then you'd have to do some work.

If the TTimer solution is working, then don't mess with it.
however, here is an example of using a  simple replacement for a TTimer, using a TThread in a service

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;
 
type TReplacementForTimersThread = class(TThread)
  private
    fInterval: integer;
    fOnTimer: TNotifyEvent;
  protected
    procedure Execute; override;
  public
    constructor Create; overload; // you can call the create in many wanys, it is up to you
    constructor Create( Interval_: integer ); overload;
    constructor Create( Interval_: integer; TimerEvent_: TNotifyEvent); overload;
    property OnTimer: TNotifyEvent read fOnTimer write fOnTimer;
    property Interval: integer read fInterval write fInterval;
// synchronized events
    procedure DoOnTimer;
  end;
 
type
  TService1 = class(TService)
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceExecute(Sender: TService);
  private
    { Private declarations }
    workerthread: TReplacementForTimersThread;
    procedure ThreadTimer(sender: TObject);
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;
 
var
  Service1: TService1;
 
implementation
 
{$R *.DFM}
 
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service1.Controller(CtrlCode);
end;
 
function TService1.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
 
{ TReplacementForTimersThread }
 
constructor TReplacementForTimersThread.Create;
begin
  inherited Create(True);
  FreeOnTerminate := True;
  Interval := 1000;
end;
 
constructor TReplacementForTimersThread.Create(Interval_: integer);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  Interval := Interval_;
end;
 
constructor TReplacementForTimersThread.Create(Interval_: integer; TimerEvent_: TNotifyEvent);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  Interval := Interval_;
  OnTimer := TimerEvent_;
end;
 
procedure TReplacementForTimersThread.DoOnTimer;
begin
  if assigned(fOnTimer) then
    fOnTimer(self);
end;
 
procedure TReplacementForTimersThread.Execute;
begin
  while not terminated do
  try
    sleep(fInterval); // the sleeping part
    if not terminated then Synchronize(DoOnTimer);
  except
    Terminate;
  end;
end;
 
procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  workerthread := TReplacementForTimersThread.Create( 1000, self.ThreadTimer);
  workerthread.Execute; // start the timer
  Started := True;
end;
 
procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  workerthread.Terminate;
  workerthread.Waitfor;
end;
 
procedure TService1.ServiceExecute(Sender: TService);
begin
  while not terminated do
    ServiceThread.ProcessRequests(true);
end;
 
procedure TService1.ThreadTimer(sender: TObject);
begin
  beep;
end;
 
end.

Open in new window

0
 
TheRealLokiSenior DeveloperCommented:
forgot this part

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  workerthread.Terminate;
  workerthread.Waitfor;
  Stopped := True;
end;
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 9
  • 5
  • 5
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now