A service application (Where do the variables live?)

This is the forum to discuss the Journal's content, article suggestions, etc.

Moderator: 2ffat

A service application (Where do the variables live?)

Postby tonus » Wed Mar 28, 2007 1:44 am

I started building an service application but do not understand, or overlook, the behaviour of variables in a service.

Just started a service application called TestProject1 and made a function to understand wat is going on.

Inserted this in the initial framework:
#include <stdio>
//---------------------------------------------------------------------------
void LogMsg(AnsiString pLM)
{
static bool init = true;
if (init)
{
init = false;
ShowMessage("init = true");
}
FILE *fp = fopen("C:\\Service1.log", "a");
if (fp)
{
fprintf(fp, "TEST %s %s\n",
FormatDateTime("yyyy-mm-dd hh:nn:ss.zzz", Now()).c_str(),
pLM.c_str());
fclose(fp);
}
}
//---------------------------------------------------------------------------
void __fastcall TService1::ServiceAfterInstall(TService *Sender)
{
LogMsg("AfterInstall");
}
//---------------------------------------------------------------------------

// put in a call to log for any event

//---------------------------------------------------------------------------
void __fastcall TService1::ServiceStop(TService *Sender, bool &Stopped)
{
LogMsg("Stop");
}
//---------------------------------------------------------------------------

This was the resulting log file:
TEST 2007-03-28 09:24:37.064 Create
TEST 2007-03-28 09:24:37.074 BeforeInstall
TEST 2007-03-28 09:24:37.965 AfterInstall
TEST 2007-03-28 09:24:40.478 Destroy

C:\Program Files\Borland\CBuilder5\Projects>TestProject1 /INSTALL
Gave message "init = true" [OK] followed by
Service installed successfully


TEST 2007-03-28 09:25:51.020 Create
TEST 2007-03-28 09:25:51.030 BeforeUninstall
TEST 2007-03-28 09:25:51.030 AfterInstall
TEST 2007-03-28 09:25:52.802 Destroy

C:\Program Files\Borland\CBuilder5\Projects>TestProject1 /UNINSTALL
Gave message "init = true" [OK] followed by
Service uninstalled successfully


Can anyone shed some light on this, because I've tried to convert George Tokas's Net Communications port server (that just works fine as a normal application!) to a service and some variables IN THE SAME ROUTINE seem initialized while others obviously are NOT.

Thanks, Anton.
tonus
 

Postby tonus » Wed Mar 28, 2007 3:21 am

I've had an textual error in an uninstall message
2nd try

C:\Program Files\Borland\CBuilder5\Projects>TestProject1 /INSTALL
TEST 2007-03-28 11:11:32.959 Create
TEST 2007-03-28 11:11:32.969 BeforeInstall
TEST 2007-03-28 11:11:33.680 AfterInstall
TEST 2007-03-28 11:11:35.653 Destroy
Gave message "init = true" [OK] followed by
Service installed successfully

C:\Program Files\Borland\CBuilder5\Projects>TestProject1 /UNINSTALL
TEST 2007-03-28 11:11:40.760 Create
TEST 2007-03-28 11:11:40.770 BeforeUninstall
TEST 2007-03-28 11:11:40.790 AfterUninstall
TEST 2007-03-28 11:11:41.881 Destroy
Gave message "init = true" [OK] followed by
Service uninstalled successfully

What puzzles me is that UNINSTALL invokes the Create event too ?!
AND
An initialized static variable behaves differently.
Obviously it gets initialized at each Create event.

As I want an array of pointers to point to objects created with new I want to be absolutely sure that I'm using the right variables pointing to the correct objects ...... Uptill now I don't get this right obviously.
tonus
 

Postby gtokas » Wed Mar 28, 2007 6:37 am

Maybe I'm not the right person to comment about services but I think that the OnCreate event is fired by the RunTimeLibrary which is linked to every project by the compiler to create the final executable, dll.
And since there is a call there every line is executed.
Anyway there was a warning at the article about the service...
There are 2 more bugs residing at server side of the article....
It was meant for this month to explain those but didn't make it...
One of the bugs have to do with a VERY SPECIAL case but has to be dealed.
Anyway both has to do with the TServerSocket::Socket->Connections[] array.

George Tokas.
"Father is C++ Builder. I'm C++ Killer"
Vangelis Tokas.
12 years old.
gtokas
BCBJ Editor
BCBJ Editor
 
Posts: 78
Joined: Mon Feb 13, 2006 4:41 pm
Location: Thessaloniki Greece

Postby tonus » Wed Mar 28, 2007 8:31 am

Thanks George, but as far as I am concerned, I do think I gathered some understanding of classes. That's thanks to your effort!

I'm looking forward to the article you mentioned.

Meanwhile I just moved the whole initialization into the ServiceExecute thread. I expanded the User class with a ServerSocketNumber property, and the Service class with a ServerSocketCount. It neatly sums up like this:
2007-03-28 15:59:19.396 Server socket #1 created
2007-03-28 15:59:19.406 Server socket #2 created
2007-03-28 15:59:19.406 Server socket #3 created
2007-03-28 15:59:19.406 Server socket #4 created
2007-03-28 15:59:19.406 Server socket #5 created
2007-03-28 15:59:19.406 Server socket #6 created
2007-03-28 15:59:19.417 Server socket #7 created
2007-03-28 15:59:19.417 Server socket #8 created
2007-03-28 15:59:20.178 Service opened

But then another thing arose, the Terminated value in the ServiceExecute eventhandler will not change to false. Thus the service will not finish up neatly.

MSG msg;
LogMsg("Service opened");
while (!Terminated) // should turn false ...
{
Sleep(100);
while (::PeekMessage (&msg, NULL, NULL, NULL, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage (&msg);
}
}
Server->Close();
for (int i = 0; i < MaxUsers; i++) delete Client[i];
LogMsg("Service closed");
tonus
 

Postby gtokas » Wed Mar 28, 2007 10:43 am

Hi again,
The Terminated flag (boolean, in the past we called it a flag) is changing status when the service terminates. It is a flag to indicate that the service ended and so everything has to clean up.

George.
"Father is C++ Builder. I'm C++ Killer"
Vangelis Tokas.
12 years old.
gtokas
BCBJ Editor
BCBJ Editor
 
Posts: 78
Joined: Mon Feb 13, 2006 4:41 pm
Location: Thessaloniki Greece

Postby tonus » Thu Mar 29, 2007 4:01 am

The termination problem above, boils down to the code below

void __fastcall TService1::ServiceExecute(TService *Sender)
{
//
Server->Open();
while (!Terminated)
{
Sleep(100);
ServiceThread->ProcessRequests(false);
}
Server->Close();
//
}

A Sleep(100) keeps the processor from doing almost 100% nothing.
Without that statement the processor will do ProcessRequests() obsessively, while that, in this specific thread, does most nothing ....

Is the processor somewhat like human ?
tonus
 

Postby gtokas » Mon Apr 02, 2007 4:36 am

Hello again...
>>Is the processor somewhat like human ?
No.. Its a complete idiot... Doesn't know the result of 1+1 if you don't saw the way...
>>ServiceThread->ProcessRequests(false);
try:
ServiceThread->ProcessRequests(true);
From online help:
void __fastcall ProcessRequests(bool WaitForMessage);

The sleep statement is not needed...
Since the server is working on its own thread the false flag is not needed.
We are letting the service to wait for message and not process after a sleep delay.

George.
"Father is C++ Builder. I'm C++ Killer"
Vangelis Tokas.
12 years old.
gtokas
BCBJ Editor
BCBJ Editor
 
Posts: 78
Joined: Mon Feb 13, 2006 4:41 pm
Location: Thessaloniki Greece

Postby rlebeau » Mon Apr 23, 2007 6:39 pm

tonus wrote:What puzzles me is that UNINSTALL invokes the Create event too ?!


TService is a descendant of TDataModule. An object instance has to be created and destroyed at runtime in order to do anything with the service. So yes, you will always get OnCreate and OnDestroy events regardless of whether the service is being installed/uninstalled by the user or started/stop by the SCM.

tonus wrote:An initialized static variable behaves differently.


A static variable is not persistent from one executable process to another. A static variable is initialized the first time it is reached by code, whether that be globally at process startup, or locally the first time the declaring function is called. Once a static variable is initialized, its value is persistent for the lifetime of the calling process, and can be changed as needed, but its value is not automatically saved when the process terminates. You have to do that yourself in your own code if you need it. This applies to all project types, not just services only.

When you run the service executable with the /install or /uninstall command-line parameter, the executable creates the TService instance, then asks it to add/remove the necessary Registry values as needed, and then the process ends. The actual service is not run.

When you start the service via the SCM, the executable creates the TService instance, then sets up the callback hooks that the SCM uses to control the service, and then the executable remains running until the service is eventually stopped.

tonus wrote:As I want an array of pointers to point to objects created with new I want to be absolutely sure that I'm using the right variables pointing to the correct objects


You will - but only withing the scope of a single process. If you are expecting to create the objects when you install the service, and then use them when the service is started, then that will not work.

tonus wrote:Uptill now I don't get this right obviously.


What exactly are you doing?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Postby gtokas » Tue Apr 24, 2007 11:01 am

Hi Gambit,

>>What exactly are you doing?

Tonus it trying to create a service for a custom TCP/IP server using methods described at my "Network Communications with BCB" articles...
I hope my article of this month to be helpful for tonus and everyone else want to do so something similar.

I also hope that everybody understands that the "Network Communications with BCB" series, "Cryptography with BCB" series and "Random Number Generation" are connected...

Regards,
George.
"Father is C++ Builder. I'm C++ Killer"
Vangelis Tokas.
12 years old.
gtokas
BCBJ Editor
BCBJ Editor
 
Posts: 78
Joined: Mon Feb 13, 2006 4:41 pm
Location: Thessaloniki Greece

Postby gtokas » Tue Apr 24, 2007 11:04 am

One more thing if I may...
>>TService is a descendant of TDataModule

Didn't get that...
Maybe aging clouds my mind here....
Can you please be a bit more specific??

George.
"Father is C++ Builder. I'm C++ Killer"
Vangelis Tokas.
12 years old.
gtokas
BCBJ Editor
BCBJ Editor
 
Posts: 78
Joined: Mon Feb 13, 2006 4:41 pm
Location: Thessaloniki Greece

Postby gtokas » Tue Apr 24, 2007 11:11 am

Forget my last post please.
When English is not your matternal language too many misunderstandings are certain...
I had to RTFM (online help) to get it straight about the TDataModule...

George.
"Father is C++ Builder. I'm C++ Killer"
Vangelis Tokas.
12 years old.
gtokas
BCBJ Editor
BCBJ Editor
 
Posts: 78
Joined: Mon Feb 13, 2006 4:41 pm
Location: Thessaloniki Greece

Postby tonus » Wed Apr 25, 2007 12:00 pm

What exactly are you doing?


Well I started off following a too simple method, and banged against the wall straigth away!
Having built several bcb projects and being pleasantly surprised by so much already being there. (I also did assembler programming, even build some services guided by an early Peter Norton book. But that was more than a decade ago.)
I started surveying the readily available methods and events in the TService component, assuming a behaviour similar to that of TApplication. So I set up a logging routine that would write all events as they were called.
After that it would seem appropriate to setup a class and initialize that in the OnCreate event ....
Well don't know if you are still reading or laughing right out loud, but for me it took a while to find out that the framework for TService is quite different from TApplication and yes reading is my weakest point.

This thread was definitely intended to both find a solution and find a "sparring partner", not to do something odd. And I surely hope others that are trapped the same way may read your clear and concise explanations.
Now I've read them I know I should have known better.

Meanwhile I've build a bcb service that as a client communicates to remote some process applications. On the other end it is a server to delphi services that have access to databases. Finally reduced that to the minimum essential.
It runs for several weeks now ....without an itch.
Using bcb components as they came with bcb 5 pro.

Regards,
Anton.
tonus
 


Return to Articles

Who is online

Users browsing this forum: No registered users and 1 guest

cron