Article ID: 201349
Article Last Modified on 11/21/2006
//**********************************************************************
//
// Bare Bones Service
//
// This program is a mere skeleton for a Windows NT/Windows 2000
// service. In its current state, it provides virtually no useful
// functionality whatsoever. Do with it as you will, but keep in
// mind the following...
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1999 Microsoft Corporation. All rights reserved.
// Author: Jonathan Russ (jruss)
//
//**********************************************************************
#define _WIN32_WINNT 0x0400
#define SERVICE_NAME TEXT("BareBonesService")
#include <windows.h>
// declare global handle for the ServiceMain() thread
HANDLE g_hServiceMainThread = NULL;
// declare global handle for the completion port that
// will be used to pass service control requests to the
// ServiceMain() thread.
HANDLE g_hCompPort = NULL;
void WINAPI ServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
void WINAPI ServiceHandler( DWORD dwControlCode );
void main( void ) {
SERVICE_TABLE_ENTRY ste[] = {
{ SERVICE_NAME, ServiceMain },
{ NULL, NULL }
};
StartServiceCtrlDispatcher( ste );
// Wait for the ServiceMain() thread to exit.
if ( g_hServiceMainThread )
WaitForSingleObject( g_hServiceMainThread, INFINITE );
// Release global thread handle.
CloseHandle( g_hServiceMainThread );
return;
}
void WINAPI ServiceMain( DWORD dwArgc, LPTSTR *lpszArgv ) {
SERVICE_STATUS ss;
SERVICE_STATUS_HANDLE hService;
DWORD dwBytesTransferred;
DWORD dwControlCode;
OVERLAPPED * po;
// Set static members of service status structure.
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS; // one service
ss.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE
| SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
// Set error members of service status structure.
ss.dwWin32ExitCode = NO_ERROR;
ss.dwServiceSpecificExitCode = NO_ERROR;
// Create a duplicate of this thread's handle so the
// primary thread can wait on it before exiting.
if ( !DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &g_hServiceMainThread, 0, 0,
DUPLICATE_SAME_ACCESS ) ) {
g_hServiceMainThread = NULL;
goto cleanup;
}
// Create the completion port.
g_hCompPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE,
NULL, 0, 0 );
if ( !g_hCompPort )
goto cleanup;
// Register the ServiceHandler() function to receive control requests.
hService = RegisterServiceCtrlHandler( SERVICE_NAME,
ServiceHandler );
// Set service status to start pending.
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwCheckPoint = 1;
ss.dwWaitHint = 500;
SetServiceStatus( hService, &ss );
// TODO: add additional initialization code here.
// set service status to running
ss.dwCurrentState = SERVICE_RUNNING;
ss.dwCheckPoint = ss.dwWaitHint = 0;
SetServiceStatus( hService, &ss );
do {
GetQueuedCompletionStatus( g_hCompPort, &dwBytesTransferred,
&dwControlCode, &po, INFINITE );
switch (dwControlCode) {
case SERVICE_CONTROL_PAUSE:
if ( ss.dwCurrentState == SERVICE_RUNNING ) {
// set service status to pause pending
ss.dwCurrentState = SERVICE_PAUSE_PENDING;
ss.dwCheckPoint = 1;
ss.dwWaitHint = 500;
SetServiceStatus( hService, &ss );
// TODO: pause all execution here.
// set service status to paused
ss.dwCurrentState = SERVICE_PAUSED;
ss.dwCheckPoint = ss.dwWaitHint = 0;
SetServiceStatus( hService, &ss );
}
break;
case SERVICE_CONTROL_CONTINUE:
if ( ss.dwCurrentState == SERVICE_PAUSED ) {
// set service status to continue pending
ss.dwCurrentState = SERVICE_CONTINUE_PENDING;
ss.dwCheckPoint = 1;
ss.dwWaitHint = 500;
SetServiceStatus( hService, &ss );
// TODO: continue execution here.
// set service status to running
ss.dwCurrentState = SERVICE_RUNNING;
ss.dwCheckPoint = ss.dwWaitHint = 0;
SetServiceStatus( hService, &ss );
}
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
if ( ss.dwCurrentState == SERVICE_RUNNING ) {
// set service status to stop pending
ss.dwCurrentState = SERVICE_STOP_PENDING;
ss.dwCheckPoint = 1;
ss.dwWaitHint = 500;
SetServiceStatus( hService, &ss );
}
break;
case SERVICE_CONTROL_INTERROGATE:
ss.dwCheckPoint = ss.dwWaitHint = 0;
SetServiceStatus( hService, &ss );
break;
}
} while ( ss.dwCurrentState != SERVICE_STOP_PENDING );
cleanup:
// TODO: perform cleanup work here.
// set service status to stopped
ss.dwCurrentState = SERVICE_STOPPED;
ss.dwCheckPoint = ss.dwWaitHint = 0;
SetServiceStatus( hService, &ss );
// Safely perform final cleanup work while confidently
// knowing the primary thread will not terminate this thread.
CloseHandle( g_hCompPort );
}
void WINAPI ServiceHandler( DWORD dwControlCode ) {
// Post status to a completion port to avoid tying up
// the primary thread.
PostQueuedCompletionStatus( g_hCompPort, 0, dwControlCode, NULL );
}
Additional query words: kbDSupport
Keywords: kbapi kbdll kbkernbase kbprb kbscm kbservice KB201349