home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
s
/
servic.zip
/
SIMPLE.C
< prev
Wrap
C/C++ Source or Header
|
1993-02-08
|
14KB
|
455 lines
///////////////////////////////////////////////////////
//
// Service.c --
// main program for Service sample.
//
// This service simply opens a named pipe
// (called \\.\pipe\simple), and reads from it.
// It then mangles the data passed in and writes
// the result back out to the pipe.
//
// The simple service will respond to the basic
// service controller functions, i.e. Start,
// Stop, and Pause.
//
// Copyright 1993, Microsoft Corp.
// All Rights Reserved
//
// history:
// who when what
// --- ---- ----
// davidbro 2/2/93 creation
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
// this event is signalled when the
// worker thread ends
//
HANDLE hServDoneEvent = NULL;
SERVICE_STATUS ssStatus; // current status of the service
SERVICE_STATUS_HANDLE sshStatusHandle;
DWORD dwGlobalErr;
DWORD TID = 0;
HANDLE threadHandle = NULL;
HANDLE pipeHandle;
// declare the service threads:
//
VOID service_main(DWORD dwArgc, LPTSTR *lpszArgv);
VOID service_ctrl(DWORD dwCtrlCode);
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint);
VOID StopSampleService(LPTSTR lpszMsg);
VOID die(char *reason);
VOID worker_thread(VOID *notUsed);
VOID StopSimpleService(LPTSTR lpszMsg);
// main() --
// all main does is call StartServiceCtrlDispatcher
// to register the main service thread. When the
// API returns, the service has stopped, so exit.
//
VOID
main()
{
SERVICE_TABLE_ENTRY dispatchTable[] = {
{ TEXT("SimpleService"), (LPSERVICE_MAIN_FUNCTION)service_main },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(dispatchTable)) {
StopSimpleService("StartServiceCtrlDispatcher failed.");
}
}
// service_main() --
// this function takes care of actually starting the service,
// informing the service controller at each step along the way.
// After launching the worker thread, it waits on the event
// that the worker thread will signal at its termination.
//
VOID
service_main(DWORD dwArgc, LPTSTR *lpszArgv)
{
DWORD dwWait;
PSECURITY_DESCRIPTOR pSD;
SECURITY_ATTRIBUTES sa;
// register our service control handler:
//
sshStatusHandle = RegisterServiceCtrlHandler(
TEXT("SimpleService"),
service_ctrl);
if (!sshStatusHandle)
goto cleanup;
// SERVICE_STATUS members that don't change in example
//
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode = 0;
// report the status to Service Control Manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
1, // checkpoint
3000)) // wait hint
goto cleanup;
// create the event object. The control handler function signals
// this event when it receives the "stop" control code.
//
hServDoneEvent = CreateEvent(
NULL, // no security attributes
TRUE, // manual reset event
FALSE, // not-signalled
NULL); // no name
if (hServDoneEvent == (HANDLE)NULL)
goto cleanup;
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
2, // checkpoint
3000)) // wait hint
goto cleanup;
// create a security descriptor that allows anyone to write to
// the pipe...
//
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pSD == NULL) {
StopSimpleService("LocalAlloc pSD failed");
return;
}
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
StopSimpleService("InitializeSecurityDescriptor failed");
LocalFree((HLOCAL)pSD);
return;
}
// add a NULL disc. ACL to the security descriptor.
//
if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE)) {
StopSimpleService("SetSecurityDescriptorDacl failed");
LocalFree((HLOCAL)pSD);
return;
}
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = TRUE; // why not...
// open our named pipe...
//
pipeHandle = CreateNamedPipe(
"\\\\.\\pipe\\simple", // name of pipe
PIPE_ACCESS_DUPLEX, // pipe open mode
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT, // pipe IO type
1, // number of instances
0, // size of outbuf (0 == allocate as necessary)
0, // size of inbuf
1000, // default time-out value
&sa); // security attributes
if (!pipeHandle) {
StopSimpleService("CreateNamedPipe");
LocalFree((HLOCAL)pSD);
return;
}
// start the thread that performs the work of the service.
//
threadHandle = CreateThread(
NULL, // security attributes
0, // stack size (0 means inherit parent's stack size)
(LPTHREAD_START_ROUTINE)worker_thread,
NULL, // argument to thread
0, // thread creation flags
&TID); // pointer to thread ID
if (!threadHandle)
goto cleanup;
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_RUNNING, // service state
NO_ERROR, // exit code
0, // checkpoint
0)) // wait hint
goto cleanup;
// wait indefinitely until hServDoneEvent is signaled.
//
dwWait = WaitForSingleObject(
hServDoneEvent, // event object
INFINITE); // wait indefinitely
cleanup:
if (hServDoneEvent != NULL)
CloseHandle(hServDoneEvent);
// try to report the stopped status to the service control manager.
//
if (sshStatusHandle != NULL)
(VOID)ReportStatusToSCMgr(
SERVICE_STOPPED,
dwGlobalErr,
0,
0);
// When SERVICE MAIN FUNCTION returns in a single service
// process, the StartServiceCtrlDispatcher function in
// the main thread returns, terminating the process.
//
return;
}
// service_ctrl() --
// this function is called by the Service Controller whenever
// someone calls ControlService in reference to our service.
//
VOID
service_ctrl(DWORD dwCtrlCode)
{
DWORD dwState = SERVICE_RUNNING;
// Handle the requested control code.
//
switch(dwCtrlCode) {
// Pause the service if it is running.
//
case SERVICE_CONTROL_PAUSE:
if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
SuspendThread(threadHandle);
dwState = SERVICE_PAUSED;
}
break;
// Resume the paused service.
//
case SERVICE_CONTROL_CONTINUE:
if (ssStatus.dwCurrentState == SERVICE_PAUSED) {
ResumeThread(threadHandle);
dwState = SERVICE_RUNNING;
}
break;
// Stop the service.
//
case SERVICE_CONTROL_STOP:
dwState = SERVICE_STOP_PENDING;
// Report the status, specifying the checkpoint and waithint,
// before setting the termination event.
//
ReportStatusToSCMgr(
SERVICE_STOP_PENDING, // current state
NO_ERROR, // exit code
1, // checkpoint
3000); // waithint
SetEvent(hServDoneEvent);
return;
// Update the service status.
//
case SERVICE_CONTROL_INTERROGATE:
break;
// invalid control code
//
default:
break;
}
// send a status response.
//
ReportStatusToSCMgr(dwState, NO_ERROR, 0, 0);
}
// worker_thread() --
// this function does the actual nuts and bolts work that
// the service requires. It will also Pause or Stop when
// asked by the service_ctrl function.
//
VOID
worker_thread(VOID *notUsed)
{
char inbuf[80];
char outbuf[80];
BOOL ret;
DWORD bytesRead;
DWORD bytesWritten;
// okay, our pipe has been creating, let's enter the simple
// processing loop...
//
while (1) {
// wait for a connection...
//
ConnectNamedPipe(pipeHandle, NULL);
// grab whatever's coming through the pipe...
//
ret = ReadFile(
pipeHandle, // file to read from
inbuf, // address of input buffer
sizeof(inbuf), // number of bytes to read
&bytesRead, // number of bytes read
NULL); // overlapped stuff, not needed
if (!ret)
// pipe's broken... go back and reconnect
//
continue;
// munge the string
//
sprintf(outbuf, "foo! [%s]", inbuf);
// send it back out...
//
ret = WriteFile(
pipeHandle, // file to write to
outbuf, // address of output buffer
sizeof(outbuf), // number of bytes to write
&bytesWritten, // number of bytes written
NULL); // overlapped stuff, not needed
if (!ret)
// pipe's broken... go back and reconnect
//
continue;
// drop the connection...
//
DisconnectNamedPipe(pipeHandle);
}
}
// utility functions...
// ReportStatusToSCMgr() --
// This function is called by the ServMainFunc() and
// ServCtrlHandler() functions to update the service's status
// to the service control manager.
//
BOOL
ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint)
{
BOOL fResult;
// Disable control requests until the service is started.
//
if (dwCurrentState == SERVICE_START_PENDING)
ssStatus.dwControlsAccepted = 0;
else
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
// These SERVICE_STATUS members are set from parameters.
//
ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwCheckPoint = dwCheckPoint;
ssStatus.dwWaitHint = dwWaitHint;
// Report the status of the service to the service control manager.
//
if (!(fResult = SetServiceStatus(
sshStatusHandle, // service reference handle
&ssStatus))) { // SERVICE_STATUS structure
// If an error occurs, stop the service.
//
StopSimpleService("SetServiceStatus");
}
return fResult;
}
// The StopSimpleService function can be used by any thread to report an
// error, or stop the service.
//
VOID
StopSimpleService(LPTSTR lpszMsg)
{
CHAR chMsg[256];
HANDLE hEventSource;
LPTSTR lpszStrings[2];
dwGlobalErr = GetLastError();
// Use event logging to log the error.
//
hEventSource = RegisterEventSource(NULL,
TEXT("SimpleService"));
sprintf(chMsg, "SimpleService error: %d", dwGlobalErr);
lpszStrings[0] = chMsg;
lpszStrings[1] = lpszMsg;
if (hEventSource != NULL) {
ReportEvent(hEventSource, // handle of event source
EVENTLOG_ERROR_TYPE, // event type
0, // event category
0, // event ID
NULL, // current user's SID
2, // strings in lpszStrings
0, // no bytes of raw data
lpszStrings, // array of error strings
NULL); // no raw data
(VOID) DeregisterEventSource(hEventSource);
}
// Set a termination event to stop SERVICE MAIN FUNCTION.
//
SetEvent(hServDoneEvent);
}