Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Writing a TService descendant 1

Status
Not open for further replies.

Griffyn

Programmer
Jul 11, 2002
1,077
AU
Hi all,

I'm in the midst of writing a number of different service applications. I've developed a framework I'm happy with that involves a service having an Access database that's used for configuration settings and logging, and can also be used for whatever specific purpose that service application requires.

The code to handle logging, initializing, and reading/writing variables runs to a few hundred lines, so after copying these functions from project to project, making small changes along the way to improve things and having the first projects having older code, I thought I could easily make a descendant class of TService. So I did. Compiles and works great. Except when I went back and opened one of these projects that I'd converted to the new TService descendant, I started getting errors.

The errors related to published properties that weren't available, such as Display Name, which is a published property of TService. There were others as well. I clicked 'Ignore' to them, and noticed that my service application 'form', instead of looking like a TDatamodule form, now looks like a regular form.

I started from fresh with the most basic of code to see if I can replicate the error, and I can. This code:

Code:
[navy][i]{---- .DPR file ----}[/i][/navy]
[b]program[/b] Project1;

[b]uses[/b]
  SvcMgr,
  Unit1 [b]in[/b] [teal]'Unit1.pas'[/teal] [navy][i]{Service1: TService}[/i][/navy];

[navy][i]{$R *.RES}[/i][/navy]

[b]begin[/b]
  Application.Initialize;
  Application.CreateForm(TService1, Service1);
  Application.Run;
[b]end[/b].
Code:
[navy][i]{---- .PAS file ----}[/i][/navy]
[b]unit[/b] Unit1;

[b]interface[/b]

[b]uses[/b]
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  NuSvc;  [navy][i]// added NuSvc reference
[/i][/navy]
[b]type[/b]
  TService1 = [b]class[/b](TNuService)  [navy][i]// changed from TService
[/i][/navy]  [b]private[/b]
    [navy][i]{ Private declarations }[/i][/navy]
  [b]public[/b]
    [b]function[/b] GetServiceController: TServiceController; [b]override[/b];
    [navy][i]{ Public declarations }[/i][/navy]
  [b]end[/b];

[b]var[/b]
  Service1: TService1;

[b]implementation[/b]

[navy][i]{$R *.DFM}[/i][/navy]

[b]procedure[/b] ServiceController(CtrlCode: DWord); stdcall;
[b]begin[/b]
  Service1.Controller(CtrlCode);
[b]end[/b];

[b]function[/b] TService1.GetServiceController: TServiceController;
[b]begin[/b]
  Result := ServiceController;
[b]end[/b];

[b]end[/b].
Code:
[navy][i]{---- NuSvc unit ----}[/i][/navy]
[b]unit[/b] NuSvc;

[b]interface[/b]

[b]uses[/b]
  SvcMgr;

[b]type[/b]
  TNuService = [b]class[/b](TService)
  [b]end[/b];

[b]implementation[/b]

[b]end[/b].

produces the error. All I did was create a new service application, add the NuSvc reference, and change TService to TNuService. Compiles fine. Close, won't reload correctly.

Using Delphi 6. Everything looks as though it should work. It makes no sense that this shouldn't work, because all I'm doing is inserting my service class between TService1 and TService anyway.

Maybe I just need some fresh eyes and brains. Anyone got any clues?
 
don't you have a service1.dfm file?

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Hi whorsdaddy,

I should have included it. I've learned already when changing class types to check the .dfm file.
Code:
object Service1: TService1
  OldCreateOrder = False
  DisplayName = 'Service1'
  Left = 191
  Top = 107
  Height = 150
  Width = 215
end

So you can see nothing should be changed here. The reference is only to TService1, not TService.
 
in fact Tservice is never meant to be overriden.

the reason why you get a form instead of a datamodule is to be found SvcMgr.pas :

Code:
procedure TServiceApplication.CreateForm(InstanceClass: TComponentClass;
  var Reference);
begin
  if InstanceClass.InheritsFrom(TService) then
  begin
    try
      TComponent(Reference) := InstanceClass.Create(Self);
    except
      TComponent(Reference) := nil;
      raise;
    end;
  end else
    Forms.Application.CreateForm(InstanceClass, Reference);
end;

as you can it checks for TService, this means your trick won't work...

I always tend to create a separate custom TThread class and start this one at service start...

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
need to correct myself.

at runtime it passes the

'InstanceClass.InheritsFrom(TService)' line, but for some reason it doesn't do this at designtime...

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
The InheritsFrom checks against InstanceClass, which in my example would be passed TService1 - so it wouldn't care that I've inserted TNuService just prior in the chain. There must be a designtime library that has different, more explicit code.

Frustrating. I've rewritten my service descendant as a plain ole unit of procedures and functions. Messy, coz it has global vars, and requires a couple of initialization calls. But at least it's better than copy and paste.

Thanks for trying whorsdaddy :)
 
like I said, descend your class from TThread and spark the thread at service startup...

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top