/* chapter 13. servicesk.c
serversk modified to be a windows service.
this is, however, a general-purpose wrapper. */
#include "evrythng.h"
#include "clntsrvr.h"
#define update_time 1000 /* one second between updates. */
void logevent (lpctstr, dword, bool);
void winapi servicemain (dword argc, lptstr argv []);
void winapi serverctrlhandlerex(dword, dword, lpvoid, lpvoid);
void updatestatus (int, int); /* calls setservicestatus. */
int servicespecific (int, lptstr *); /* former main program. */
volatile static bool shutdown = false, pauseflag = false;
static service_status hservstatus;
static service_status_handle hsstat; /* handle to set status. */
static lptstr servicename = _t ("socketcommandlineservice");
static lptstr logfilename = _t ("commandlineservicelog.txt");
/* main routine that starts the service control dispatcher. */
void _tmain (int argc, lptstr argv [])
{
service_table_entry dispatchtable [] =
{
{ servicename, servicemain },
{ null, null }
};
startservicectrldispatcher (dispatchtable);
return 0;
}
/* servicemain entry point, called when the service is created. */
void winapi servicemain (dword argc, lptstr argv [])
{
dword i, context = 1;
/* set the current directory and open a log file, appending to
an existing file. */
/* set all server status data members. */
hservstatus.dwservicetype = service_win32_own_process;
hservstatus.dwcurrentstate = service_start_pending;
hservstatus.dwcontrolsaccepted = service_accept_stop |
service_accept_shutdown | service_accept_pause_continue;
hservstatus.dwwin32exitcode = error_service_specif0c_error;
hservstatus.dwservicespecificexitcode = 0;
hservstatus.dwcheckpoint = 0;
hservstatus.dwwaithint = 2 * cs_timeout;
hsstat = registerservicectrlhandlerex (servicename,
serverctrlhandler, &context);
setservicestatus (hsstat, &hservstatus);
/* start service-specific work; generic work is complete. */
if (servicespecific (argc, argv) != 0) {
hservstatus.dwcurrentstate = service_stopped;
hservstatus.dwservicespecificexitcode = 1;
/* server initialization failed. */
setservicestatus (hsstat, &hservstatus);
return;
}
/* we will only return here when the servicespecific function
completes, indicating system shutdown. */
updatestatus (service_stopped, 0);
return;
}
void updatestatus (int newstatus, int check)
/* set a new service status and checkpoint --
either specific value or increment. */
{
if (check < 0) hservstatus.dwcheckpoint++;
else hservstatus.dwcheckpoint = check;
if (newstatus >= 0) hservstatus.dwcurrentstate = newstatus;
setservicestatus (hsstat, &hservstatus);
return;
}
/* control handler function, invoked by the scm to run */
/* in the same thread as the main program. */
/* the last three parameters are not used, and the pre-nt5 */
/* handlers would also work in this example. */
void winapi serverctrlhandlerex (dword control, dword eventtype,
lpvoid lpeventdata, lpvoid lpcontext)
{
switch (control) {
case service_control_shutdown:
case service_control_stop:
shutdown = true; /* set the global shutdown flag. */
updatestatus (service_stop_pending, -1);
break;
case service_control_pause:
pauseflag = true; /* interrogated periodically. */
break;
case service_control_continue:
pauseflag = false;
break;
case service_control_interrogate:
break;
default:
if (control > 127 && control < 256) /* user defined. */
break;
}
updatestatus (-1, -1); /* increment checkpoint. */
return;
}
/* this is the service-specific function, or "main," and is
called from the more generic servicemain.
in general, you can take any server, such as servernp.c, and
rename "main" as "servicespecific"; putting code right here.
but some changes are required to update status. */
int servicespecific (int argc, lptstr argv [])
{
updatestatus (-1, -1); /* increment the checkpoint. */
/* ... initialize system ... */
/* be sure to update the checkpoint periodically. */
return 0;
}