Solved

novice Service writer

Posted on 2008-10-15
22
268 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:mikesExpertExchange
  • 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 100 total points
ID: 22723956
A question,

is your service set to interact with the desktop?
0
 
LVL 1

Author Comment

by:mikesExpertExchange
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:mikesExpertExchange
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:mikesExpertExchange
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:mikesExpertExchange
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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:mikesExpertExchange
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:mikesExpertExchange
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:mikesExpertExchange
ID: 22725832
nevermind that last question...i didn't know it was a constant in delphi...
0
 
LVL 14

Accepted Solution

by:
SteveBay earned 400 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:mikesExpertExchange
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:mikesExpertExchange
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Mydac connection data base issue 3 135
Delphi IDE crash without error message ... 7 75
TServerSocket - file via sendbuf or Text via sendtext ? 1 42
DBGrid or StringGrid ? 6 63
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

929 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

19 Experts available now in Live!

Get 1:1 Help Now