?
Solved

novice Service writer

Posted on 2008-10-15
22
Medium Priority
?
275 Views
Last Modified: 2012-06-27
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
Comment
Question by:Michael Sterling
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 5
  • 5
  • +1
22 Comments
 
LVL 18

Expert Comment

by:Johnjces
ID: 22723892
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
 
LVL 18

Expert Comment

by:Johnjces
ID: 22723948
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
 
LVL 18

Assisted Solution

by:Johnjces
Johnjces earned 400 total points
ID: 22723956
A question,

is your service set to interact with the desktop?
0
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.

 
LVL 1

Author Comment

by:Michael Sterling
ID: 22724009
no its not set to interact with the desktop. is that the problem?
0
 
LVL 18

Expert Comment

by:Johnjces
ID: 22724040
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
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22724271
i think i need to make/declare the service as a system process maybe. how do i do that?
0
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22724852
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
 
LVL 14

Expert Comment

by:SteveBay
ID: 22725057
Change the Display Name in the properties of the TService.
0
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22725237
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
 
LVL 14

Expert Comment

by:SteveBay
ID: 22725614
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
 
LVL 14

Expert Comment

by:SteveBay
ID: 22725635
Note: Add DateUtils to your uses clause
0
 
LVL 18

Expert Comment

by:Johnjces
ID: 22725647
Ahh, are you using Vista? That will certainly make some differences!

John
0
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22725706
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
 
LVL 14

Expert Comment

by:SteveBay
ID: 22725729
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
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22725757
and...i can IncSecond(FLastTime, 1) to add a second  but how do i multiply by one millisecond???
0
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22725832
nevermind that last question...i didn't know it was a constant in delphi...
0
 
LVL 14

Accepted Solution

by:
SteveBay earned 1600 total points
ID: 22725833
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
 
LVL 1

Author Closing Comment

by:Michael Sterling
ID: 31506412
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
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22726348
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
 
LVL 1

Author Comment

by:Michael Sterling
ID: 22732182
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
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22753892
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
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22753898
forgot this part

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

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses

718 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