Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2591 lines
63 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ts2.c
Abstract:
This is a test program for exercising the service controller. This
program acts like a service and exercises the Service Controller API
that can be called from a service:
NetServiceStartCtrlDispatcher
NetServiceRegisterCtrlHandler
NetServiceStatus
Contents:
Grumpy
Lumpy
Dumpy
Sleepy
Dead
SlowStop - Takes a long time to stop based on Message Box.
Terminate - Starts normally, After 20 seconds, it sends a STOPPED
status, and does an ExitProcess.
Bad1 - Never calls RegisterServiceCtrlHandler.
Bad2 - Stays in START_PENDING forever.
Bad3 - Start= Sends 1 START_PENDING, then doesn't send any further
status messages. Otherwise operates normally.
Bad4 - Normal Start; On Stop it sends 1 stop pending status then
terminates itself.
HangOnStop - Doesn't return from CtrlHandl routine on Stop
requests until 40 seconds has passed. (pipe timeout is 30 sec).
Sends a RUNNING status after the 40 second wait, then it sleeps
for 20 seconds before sending STOPPED status.
StartAndDie - Takes 40 seconds to start, then it terminates
right after saying it was started.
Author:
Dan Lafferty (danl) 12 Apr-1991
Environment:
User Mode -Win32
Notes:
optional-notes
Revision History:
--*/
//
// Includes
//
#include <nt.h> // DbgPrint prototype
#include <ntrtl.h> // DbgPrint prototype
#include <windef.h>
#include <nturtl.h> // needed for winbase.h
#include <winbase.h>
#include <wingdi.h> // for winuserp.h
#include <winuser.h> // MessageBox
#include <winuserp.h> // STARTF_DESKTOPINHERIT
#include <wincon.h> // CONSOLE_SCREEN_BUFFER_INFO
#include <winsvc.h>
#include <tstr.h> // Unicode string macros
#include <stdio.h> // printf
//
// Defines
//
#define INFINITE_WAIT_TIME 0xffffffff
#define NULL_STRING TEXT("");
LPWSTR pszInteractiveDesktop=L"WinSta0\\Default";
//
// Globals
//
HANDLE DbgLogFileHandle = INVALID_HANDLE_VALUE;
SERVICE_STATUS GrumpyStatus;
SERVICE_STATUS LumpyStatus;
SERVICE_STATUS DumpyStatus;
SERVICE_STATUS SleepyStatus;
SERVICE_STATUS DeadStatus;
SERVICE_STATUS SlowStopStatus;
SERVICE_STATUS TerminateStatus;
SERVICE_STATUS Bad1Status;
SERVICE_STATUS Bad2Status;
SERVICE_STATUS Bad3Status;
SERVICE_STATUS Bad4Status;
SERVICE_STATUS HangOnStopStatus;
SERVICE_STATUS StartProcStatus;
SERVICE_STATUS StartAndDieStatus;
HANDLE GrumpyDoneEvent;
HANDLE LumpyDoneEvent;
HANDLE DumpyDoneEvent;
HANDLE SleepyDoneEvent;
HANDLE DeadDoneEvent;
HANDLE SlowStopDoneEvent;
HANDLE TerminateDoneEvent;
HANDLE Bad1DoneEvent;
HANDLE Bad2DoneEvent;
HANDLE Bad3DoneEvent;
HANDLE Bad4DoneEvent;
HANDLE HangOnStopDoneEvent;
HANDLE StartProcDoneEvent;
HANDLE StartAndDieDoneEvent;
SERVICE_STATUS_HANDLE GrumpyStatusHandle;
SERVICE_STATUS_HANDLE LumpyStatusHandle;
SERVICE_STATUS_HANDLE DumpyStatusHandle;
SERVICE_STATUS_HANDLE SleepyStatusHandle;
SERVICE_STATUS_HANDLE DeadStatusHandle;
SERVICE_STATUS_HANDLE SlowStopStatusHandle;
SERVICE_STATUS_HANDLE TerminateStatusHandle;
SERVICE_STATUS_HANDLE Bad1StatusHandle;
SERVICE_STATUS_HANDLE Bad2StatusHandle;
SERVICE_STATUS_HANDLE Bad3StatusHandle;
SERVICE_STATUS_HANDLE Bad4StatusHandle;
SERVICE_STATUS_HANDLE HangOnStopStatusHandle;
SERVICE_STATUS_HANDLE StartProcStatusHandle;
SERVICE_STATUS_HANDLE StartAndDieStatusHandle;
//
// Function Prototypes
//
DWORD
GrumpyStart (
DWORD argc,
LPTSTR *argv
);
DWORD
LumpyStart (
DWORD argc,
LPTSTR *argv
);
DWORD
DumpyStart (
DWORD argc,
LPTSTR *argv
);
DWORD
SleepyStart (
DWORD argc,
LPTSTR *argv
);
DWORD
DeadStart (
DWORD argc,
LPTSTR *argv
);
DWORD
SlowStopStart (
DWORD argc,
LPTSTR *argv
);
DWORD
TerminateStart (
DWORD argc,
LPTSTR *argv
);
DWORD
Bad1Start (DWORD argc,LPTSTR *argv);
DWORD
Bad2Start (DWORD argc,LPTSTR *argv);
DWORD
Bad3Start (DWORD argc,LPTSTR *argv);
DWORD
Bad4Start (DWORD argc,LPTSTR *argv);
DWORD
HangOnStopStart (DWORD argc,LPTSTR *argv);
DWORD
StartProcStart (DWORD argc,LPTSTR *argv);
DWORD
StartAndDieStart (DWORD argc,LPTSTR *argv);
VOID
GrumpyCtrlHandler (
IN DWORD opcode
);
VOID
LumpyCtrlHandler (
IN DWORD opcode
);
VOID
DumpyCtrlHandler (
IN DWORD opcode
);
VOID
SleepyCtrlHandler (
IN DWORD opcode
);
VOID
DeadCtrlHandler (
IN DWORD opcode
);
VOID
SlowStopCtrlHandler (
IN DWORD opcode
);
VOID
TerminateCtrlHandler (
IN DWORD opcode
);
VOID
Bad1CtrlHandler (IN DWORD opcode);
VOID
Bad2CtrlHandler (IN DWORD opcode);
VOID
Bad3CtrlHandler (IN DWORD opcode);
VOID
Bad4CtrlHandler (IN DWORD opcode);
VOID
HangOnStopCtrlHandler (IN DWORD opcode);
VOID
StartProcCtrlHandler (IN DWORD opcode);
VOID
StartAndDieCtrlHandler (IN DWORD opcode);
VOID
SvcPrintf (char *Format, ...);
VOID
SetUpConsole();
/****************************************************************************/
VOID __cdecl
main (
DWORD argc,
PCHAR argv[]
)
{
DWORD i;
SERVICE_TABLE_ENTRY DispatchTable[] = {
{ TEXT("StartProc"), StartProcStart },
{ TEXT("grumpy"), GrumpyStart },
{ TEXT("lumpy"), LumpyStart },
{ TEXT("dumpy"), DumpyStart },
{ TEXT("sleepy"), SleepyStart },
{ TEXT("dead"), DeadStart },
{ TEXT("slowstop"), SlowStopStart },
{ TEXT("terminate"), TerminateStart },
{ TEXT("Bad1"), Bad1Start },
{ TEXT("Bad2"), Bad2Start },
{ TEXT("Bad3"), Bad3Start },
{ TEXT("Bad4"), Bad4Start },
{ TEXT("HangOnStop"), HangOnStopStart },
{ TEXT("StartAndDie"), StartAndDieStart },
{ NULL, NULL }
};
DbgPrint("[ts2]Args passed to .exe main() function:\n");
for (i=0; i<argc; i++) {
DbgPrint(" [TS2] CommandArg%d = %s\n", i,argv[i]);
}
//SetUpConsole();
if (!StartServiceCtrlDispatcher( DispatchTable)) {
DbgPrint("[ts2]StartServiceCtrlDispatcher returned error %d\n",GetLastError);
}
DbgPrint("[ts2]The Service Process is Terminating....\n");
ExitProcess(0);
}
/****************************************************************************/
//
// Grumpy will take a long time to respond to pause
//
//
DWORD
GrumpyStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
//---------------------------------------------------------------------
SC_HANDLE SCHandle;
SC_HANDLE ServiceHandle;
//---------------------------------------------------------------------
DbgPrint(" [GRUMPY] Inside the Grumpy Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [GRUMPY] CommandArg%d = %s\n", i,argv[i]);
}
GrumpyDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
GrumpyStatus.dwServiceType = SERVICE_WIN32;
GrumpyStatus.dwCurrentState = SERVICE_RUNNING;
GrumpyStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
//
// Set up bogus values for status.
//
GrumpyStatus.dwWin32ExitCode = 14;
GrumpyStatus.dwServiceSpecificExitCode = 55;
GrumpyStatus.dwCheckPoint = 53;
GrumpyStatus.dwWaitHint = 22;
//
// Register the Control Handler routine.
//
DbgPrint(" [GRUMPY] Getting Ready to call RegisterServiceCtrlHandler\n");
GrumpyStatusHandle = RegisterServiceCtrlHandler(
TEXT("grumpy"),
GrumpyCtrlHandler);
if (GrumpyStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [GRUMPY] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (GrumpyStatusHandle, &GrumpyStatus)) {
status = GetLastError();
DbgPrint(" [GRUMPY] SetServiceStatus error %ld\n",status);
}
#define START_SERVICE
#ifdef START_SERVICE
//---------------------------------------------------------------------
//
// TEMP CODE - Start another service
//
DbgPrint("[GRUMPY] Attempt to start Messinger");
if ((SCHandle = OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT))!= NULL) {
if ((ServiceHandle = OpenService(
SCHandle,
TEXT("Messinger"),
SERVICE_START)) != NULL) {
if (!StartService(ServiceHandle,0,NULL)) {
DbgPrint("[GRUMPY] StartService Failed, rc = %d",
GetLastError());
}
}
else {
DbgPrint("GRUMPY] OpenService failed %d\n",GetLastError());
}
}
else {
DbgPrint("GRUMPY] OpenSCManager failed %d\n",GetLastError());
}
//
//
//
//---------------------------------------------------------------------
#endif
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
GrumpyDoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [GRUMPY] Leaving the grumpy service\n");
CloseHandle(GrumpyDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
GrumpyCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [GRUMPY] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
Sleep(60000); // 1 minute
GrumpyStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
GrumpyStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
GrumpyStatus.dwWin32ExitCode = 0;
GrumpyStatus.dwServiceSpecificExitCode = 0;
GrumpyStatus.dwCurrentState = SERVICE_STOPPED;
GrumpyStatus.dwWaitHint = 0;
GrumpyStatus.dwCheckPoint = 0;
SetEvent(GrumpyDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
//
// Send a BAD Status Response
//
DbgPrint(" [GRUMPY] Sending bogus status (0x00000000)\n");
if (!SetServiceStatus (0L, &GrumpyStatus)) {
status = GetLastError();
DbgPrint(" [GRUMPY] SetServiceStatus error %ld "
" - - Expect %d\n",status,ERROR_INVALID_HANDLE);
}
DbgPrint(" [GRUMPY] Sending bogus status (0xefefefef)\n");
if (!SetServiceStatus (0xefefefef, &GrumpyStatus)) {
status = GetLastError();
DbgPrint(" [GRUMPY] SetServiceStatus error %ld "
" - - Expect %d\n",status,ERROR_INVALID_HANDLE);
}
break;
default:
DbgPrint(" [GRUMPY] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (GrumpyStatusHandle, &GrumpyStatus)) {
status = GetLastError();
DbgPrint(" [GRUMPY] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
DWORD
LumpyStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [LUMPY] Inside the Lumpy Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [LUMPY] CommandArg%d = %s\n", i,argv[i]);
}
LumpyDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
LumpyStatus.dwServiceType = SERVICE_WIN32|SERVICE_INTERACTIVE_PROCESS;
LumpyStatus.dwCurrentState = SERVICE_RUNNING;
LumpyStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;
LumpyStatus.dwWin32ExitCode = 0;
LumpyStatus.dwServiceSpecificExitCode = 0;
LumpyStatus.dwCheckPoint = 0;
LumpyStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [LUMPY] Getting Ready to call RegisterServiceCtrlHandler\n");
LumpyStatusHandle = RegisterServiceCtrlHandler(
TEXT("lumpy"),
LumpyCtrlHandler);
if (LumpyStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [LUMPY] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (LumpyStatusHandle, &LumpyStatus)) {
status = GetLastError();
DbgPrint(" [LUMPY] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
LumpyDoneEvent,
INFINITE_WAIT_TIME);
if (status == WAIT_FAILED) {
DbgPrint(" [LUMPY] WaitLastError = %d\n",GetLastError());
}
DbgPrint(" [LUMPY] Leaving the lumpy service\n");
CloseHandle(LumpyDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
LumpyCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [LUMPY] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
SvcPrintf("Lumpy received a PAUSE\n");
LumpyStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
SvcPrintf("Lumpy received a CONTINUE\n");
LumpyStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
SvcPrintf("Lumpy received a STOP\n");
LumpyStatus.dwWin32ExitCode = 0;
LumpyStatus.dwCurrentState = SERVICE_STOPPED;
if (!SetEvent(LumpyDoneEvent)) {
DbgPrint(" [LUMPY] SetEvent Failed %d\n",GetLastError());
}
break;
case SERVICE_CONTROL_INTERROGATE:
SvcPrintf("Lumpy received an INTERROGATE\n");
break;
default:
DbgPrint(" [LUMPY] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (LumpyStatusHandle, &LumpyStatus)) {
status = GetLastError();
DbgPrint(" [LUMPY] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
DWORD
DumpyStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [DUMPY] Inside the Dumpy Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [DUMPY] CommandArg%d = %s\n", i,argv[i]);
}
DumpyDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
DumpyStatus.dwServiceType = SERVICE_WIN32;
DumpyStatus.dwCurrentState = SERVICE_RUNNING;
DumpyStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
DumpyStatus.dwWin32ExitCode = 0;
DumpyStatus.dwServiceSpecificExitCode = 0;
DumpyStatus.dwCheckPoint = 0;
DumpyStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [DUMPY] Getting Ready to call RegisterServiceCtrlHandler\n");
DumpyStatusHandle = RegisterServiceCtrlHandler(
TEXT("dumpy"),
DumpyCtrlHandler);
if (DumpyStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [DUMPY] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (DumpyStatusHandle, &DumpyStatus)) {
status = GetLastError();
DbgPrint(" [DUMPY] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
DumpyDoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [DUMPY] Leaving the dumpy service\n");
CloseHandle(DumpyDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
DumpyCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [DUMPY] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
DumpyStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
DumpyStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
DumpyStatus.dwWin32ExitCode = 0;
DumpyStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(DumpyDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [DUMPY] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (DumpyStatusHandle, &DumpyStatus)) {
status = GetLastError();
DbgPrint(" [DUMPY] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
DWORD
SleepyStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DWORD checkpoint=1;
DbgPrint(" [SLEEPY] Inside the Sleepy Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [SLEEPY] CommandArg%d = %s\n", i,argv[i]);
}
SleepyDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
SleepyStatus.dwServiceType = SERVICE_WIN32;
SleepyStatus.dwCurrentState = SERVICE_START_PENDING;
SleepyStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
SleepyStatus.dwWin32ExitCode = 0;
SleepyStatus.dwServiceSpecificExitCode = 0;
SleepyStatus.dwCheckPoint = checkpoint++;
SleepyStatus.dwWaitHint = 40000;
//
// Register the Control Handler routine.
//
DbgPrint(" [SLEEPY] Getting Ready to call RegisterServiceCtrlHandler\n");
SleepyStatusHandle = RegisterServiceCtrlHandler(
TEXT("sleepy"),
SleepyCtrlHandler);
if (SleepyStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [SLEEPY] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// This service tests the install pending system in the service
// controller. Therefore, it loops and sleeps 4 times prior to
// indicating that installation is complete.
//
for (i=0; i<5; i++) {
//
// Return the status
//
DbgPrint(" [SLEEPY] sending install status #%d\n",i);
if (!SetServiceStatus (SleepyStatusHandle, &SleepyStatus)) {
status = GetLastError();
DbgPrint(" [SLEEPY] SetServiceStatus error %ld\n",status);
}
Sleep(20000); // Sleep for 20 seconds
status = WaitForSingleObject (
SleepyDoneEvent,
0);
if (status == 0) {
DbgPrint(" [SLEEPY] terminated while installing\n");
return(NO_ERROR);
}
//
// Increment the checkpoint value in status. (20 seconds)
//
SleepyStatus.dwCheckPoint = checkpoint++;
SleepyStatus.dwWaitHint = 40000;
DbgPrint(" [SLEEPY] checkpoint = 0x%lx\n",SleepyStatus.dwCheckPoint);
#ifdef SpecialTest
//
//******************************************************************
// TEST out the condition where we have an unsolicited uninstall
// after sending the first status message.
//
SleepyStatus.dwWin32ExitCode = 0;
SleepyStatus.dwCurrentState = SERVICE_STOPPED;
if (!SetServiceStatus (SleepyStatusHandle, &SleepyStatus)) {
status = GetLastError();
DbgPrint("[SLEEPY] Error From SetServiceStatus %d\n",status);
}
DbgPrint(" [SLEEPY] Leaving the Sleepy service\n");
return(NO_ERROR);
//
//******************************************************************
#endif //SpecialTest
}
DbgPrint(" [SLEEPY] setting up installed status\n");
SleepyStatus.dwCurrentState = SERVICE_RUNNING;
SleepyStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
SleepyStatus.dwWin32ExitCode = 0;
SleepyStatus.dwServiceSpecificExitCode = 0;
SleepyStatus.dwCheckPoint = 0;
SleepyStatus.dwWaitHint = 0;
DbgPrint(" [SLEEPY] sending install status #%d\n",i);
if (!SetServiceStatus (SleepyStatusHandle, &SleepyStatus)) {
status = GetLastError();
DbgPrint(" [SLEEPY] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
SleepyDoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [SLEEPY] Leaving the Sleepy service\n");
CloseHandle(SleepyDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
SleepyCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [SLEEPY] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
SleepyStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
SleepyStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
SleepyStatus.dwWin32ExitCode = 0;
SleepyStatus.dwCheckPoint = 0;
SleepyStatus.dwWaitHint = 0;
SleepyStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(SleepyDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [SLEEPY] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (SleepyStatusHandle, &SleepyStatus)) {
status = GetLastError();
DbgPrint(" [SLEEPY] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
DWORD
DeadStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [DEAD] Inside the Dead Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [DEAD] CommandArg%d = %s\n", i,argv[i]);
}
DeadDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
DeadStatus.dwServiceType = SERVICE_WIN32;
DeadStatus.dwCurrentState = SERVICE_STOPPED;
DeadStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
DeadStatus.dwWin32ExitCode = 0x00020002;
DeadStatus.dwServiceSpecificExitCode = 0;
DeadStatus.dwCheckPoint = 0;
DeadStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [DEAD] Getting Ready to call RegisterServiceCtrlHandler\n");
DeadStatusHandle = RegisterServiceCtrlHandler(
TEXT("dead"),
DeadCtrlHandler);
if (DeadStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [DEAD] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// The Dead Service will now exit process prior to sending its first
// status.
//
DbgPrint(" [DEAD] Terminating the Dead Service Process\n");
ExitProcess(0);
//
// Return the status
//
if (!SetServiceStatus (DeadStatusHandle, &DeadStatus)) {
status = GetLastError();
DbgPrint(" [DEAD] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
DeadDoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [DEAD] Leaving the dead service\n");
CloseHandle(DeadDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
DeadCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [DEAD] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
DeadStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
DeadStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
DeadStatus.dwWin32ExitCode = 0;
DeadStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(DeadDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [DEAD] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (DeadStatusHandle, &DeadStatus)) {
status = GetLastError();
DbgPrint(" [DEAD] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
//
// SlowStop will take a long time to stop.
//
//
DWORD
SlowStopStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DWORD LoopCount;
DbgPrint(" [SLOW_STOP] Inside the SlowStop Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [SLOW_STOP] CommandArg%d = %s\n", i,argv[i]);
}
SlowStopDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
SlowStopStatus.dwServiceType = SERVICE_WIN32;
SlowStopStatus.dwCurrentState = SERVICE_RUNNING;
SlowStopStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;
SlowStopStatus.dwWin32ExitCode = 0;
SlowStopStatus.dwServiceSpecificExitCode = 0;
SlowStopStatus.dwCheckPoint = 0;
SlowStopStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [SLOW_STOP] Getting Ready to call RegisterServiceCtrlHandler\n");
SlowStopStatusHandle = RegisterServiceCtrlHandler(
TEXT("slowstop"),
SlowStopCtrlHandler);
if (SlowStopStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [SLOW_STOP] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (SlowStopStatusHandle, &SlowStopStatus)) {
status = GetLastError();
DbgPrint(" [SLOW_STOP] SetServiceStatus error %ld\n",status);
}
//
// Put up a message box to get information on how long it should take
// this service to stop. The choices are to stop within the WaitHint
// time period - and to stop outside of the WaitHint time period
//
//
// Ask the user how long to take in stopping
//
status = MessageBox(
NULL,
"Press YES Stop occurs within WaitHint Period\n"
"Press NO Stop takes longer than the WaitHint Period\n"
"Press CANCEL Stop occurs within WaitHint Period",
"SlowStopStart",
MB_YESNOCANCEL | MB_SERVICE_NOTIFICATION);
DbgPrint("MessageBox return status = %d\n",status);
SvcPrintf("I got the status\n");
switch(status){
case IDNO:
LoopCount = 30;
break;
case IDYES:
LoopCount = 6;
break;
case IDCANCEL:
LoopCount = 6;
break;
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
SlowStopDoneEvent,
INFINITE_WAIT_TIME);
//===============================================
//
// When shutting down, send the STOP_PENDING
// status for 8 seconds then STOP.
// The WaitHint indicates it takes 10 seconds
// to stop.
//
//===============================================
for (i=0; i<LoopCount ; i++ ) {
Sleep(1000);
SlowStopStatus.dwCheckPoint++;
if (!SetServiceStatus (SlowStopStatusHandle, &SlowStopStatus)) {
status = GetLastError();
DbgPrint(" [SLOW_STOP] SetServiceStatus error %ld\n",status);
}
}
SlowStopStatus.dwCurrentState = SERVICE_STOPPED;
SlowStopStatus.dwCheckPoint=0;
SlowStopStatus.dwWaitHint=0;
if (!SetServiceStatus (SlowStopStatusHandle, &SlowStopStatus)) {
status = GetLastError();
DbgPrint(" [SLOW_STOP] SetServiceStatus error %ld\n",status);
}
DbgPrint(" [SLOW_STOP] Leaving the slowstop service\n");
CloseHandle(SlowStopDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
SlowStopCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [SLOW_STOP] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
SlowStopStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
SlowStopStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
SlowStopStatus.dwWin32ExitCode = 0;
SlowStopStatus.dwServiceSpecificExitCode = 0;
SlowStopStatus.dwCurrentState = SERVICE_STOP_PENDING;
SlowStopStatus.dwWaitHint = 10000; // 10 seconds to stop
// SlowStopStatus.dwWaitHint = 0; // 10 seconds to stop
SlowStopStatus.dwCheckPoint = 1;
SetEvent(SlowStopDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [SLOW_STOP] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (SlowStopStatusHandle, &SlowStopStatus)) {
status = GetLastError();
DbgPrint(" [SLOW_STOP] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
//
// Terminate will die unexpectedly.
//
//
DWORD
TerminateStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [TERMINATE] Inside the Terminate Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [TERMINATE] CommandArg%d = %s\n", i,argv[i]);
}
TerminateDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
TerminateStatus.dwServiceType = SERVICE_WIN32;
TerminateStatus.dwCurrentState = SERVICE_RUNNING;
TerminateStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
TerminateStatus.dwWin32ExitCode = 0;
TerminateStatus.dwServiceSpecificExitCode = 0;
TerminateStatus.dwCheckPoint = 0;
TerminateStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [TERMINATE] Getting Ready to call RegisterServiceCtrlHandler\n");
TerminateStatusHandle = RegisterServiceCtrlHandler(
TEXT("terminate"),
TerminateCtrlHandler);
if (TerminateStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [TERMINATE] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (TerminateStatusHandle, &TerminateStatus)) {
status = GetLastError();
DbgPrint(" [TERMINATE] SetServiceStatus error %ld\n",status);
}
//=======================================================================
//
// Sleep for 20 seconds, then send out an error status, and ExitProcess.
// NOTE: It would be more proper for a service to ExitThread here
// instead. But who says test services need to be proper?
//
//=======================================================================
Sleep(20000);
TerminateStatus.dwCurrentState = SERVICE_STOPPED;
TerminateStatus.dwWin32ExitCode = ERROR_INVALID_ENVIRONMENT;
TerminateStatus.dwCheckPoint=0;
TerminateStatus.dwWaitHint=0;
if (!SetServiceStatus (TerminateStatusHandle, &TerminateStatus)) {
status = GetLastError();
DbgPrint(" [TERMINATE] SetServiceStatus error %ld\n",status);
}
ExitProcess(NO_ERROR);
return(NO_ERROR);
}
/****************************************************************************/
VOID
TerminateCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [TERMINATE] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
TerminateStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
TerminateStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
TerminateStatus.dwWin32ExitCode = 0;
TerminateStatus.dwServiceSpecificExitCode = 0;
TerminateStatus.dwCurrentState = SERVICE_STOP_PENDING;
TerminateStatus.dwCheckPoint = 1;
TerminateStatus.dwWaitHint = 20000;
SetEvent(TerminateDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [TERMINATE] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (TerminateStatusHandle, &TerminateStatus)) {
status = GetLastError();
DbgPrint(" [TERMINATE] SetServiceStatus error %ld\n",status);
}
CloseHandle(TerminateDoneEvent);
return;
}
/****************************************************************************/
//
// Bad1 will never call RegisterServiceCtrlHandler.
//
//
DWORD
Bad1Start (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [BAD1] Inside the Bad1 Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [BAD1] CommandArg%d = %s\n", i,argv[i]);
}
Bad1DoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
Bad1Status.dwServiceType = SERVICE_WIN32;
Bad1Status.dwCurrentState = SERVICE_START_PENDING;
Bad1Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
Bad1Status.dwWin32ExitCode = 0;
Bad1Status.dwServiceSpecificExitCode = 0;
Bad1Status.dwCheckPoint = 1;
Bad1Status.dwWaitHint = 5000;
//
// Register the Control Handler routine.
//
/////////////////////////////////
// Sleep for a real long time
// without calling RegisterServiceCtrlHandler.
DbgPrint(" [BAD1] Getting Ready to sleep\n");
Sleep(9999999);
////////////////////////////////////////////////
//
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
Bad1DoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [BAD1] Leaving the Bad1 service\n");
CloseHandle(Bad1DoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
Bad1CtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [BAD1] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
Bad1Status.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
Bad1Status.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
Bad1Status.dwWin32ExitCode = 0;
Bad1Status.dwServiceSpecificExitCode = 0;
Bad1Status.dwCurrentState = SERVICE_STOP_PENDING;
Bad1Status.dwCheckPoint = 1;
Bad1Status.dwWaitHint = 20000;
SetEvent(Bad1DoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [BAD1] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (Bad1StatusHandle, &Bad1Status)) {
status = GetLastError();
DbgPrint(" [BAD1] SetServiceStatus error %ld\n",status);
}
CloseHandle(Bad1DoneEvent);
return;
}
/****************************************************************************/
//
// Bad2 will never complete initialization (stuck in START_PENDING forever).
// The control handler is functioning and STOP is functioning.
//
//
DWORD
Bad2Start (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [BAD2] Inside the Bad2 Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [BAD2] CommandArg%d = %s\n", i,argv[i]);
}
Bad2DoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
Bad2Status.dwServiceType = SERVICE_WIN32;
Bad2Status.dwCurrentState = SERVICE_START_PENDING;
Bad2Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
Bad2Status.dwWin32ExitCode = 0;
Bad2Status.dwServiceSpecificExitCode = 0;
Bad2Status.dwCheckPoint = 1;
Bad2Status.dwWaitHint = 5000;
//
// Register the Control Handler routine.
//
DbgPrint(" [BAD2] Getting Ready to call RegisterServiceCtrlHandler\n");
Bad2StatusHandle = RegisterServiceCtrlHandler(
TEXT("Bad2"),
Bad2CtrlHandler);
if (Bad2StatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [BAD2] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (Bad2StatusHandle, &Bad2Status)) {
status = GetLastError();
DbgPrint(" [BAD2] SetServiceStatus error %ld\n",status);
}
#ifdef remove
/////////////////////////////////
// Sleep for a real long time
// without sending status.
DbgPrint(" [BAD2] Getting Ready to sleep\n");
Sleep(9999999);
#endif
/////////////////////////////////
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
Bad2DoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [BAD2] Leaving the Bad2 service\n");
CloseHandle(Bad2DoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
Bad2CtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [BAD2] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
Bad2Status.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
Bad2Status.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
Bad2Status.dwWin32ExitCode = 0;
Bad2Status.dwServiceSpecificExitCode = 0;
Bad2Status.dwCurrentState = SERVICE_STOPPED;
Bad2Status.dwCheckPoint = 1;
Bad2Status.dwWaitHint = 5000;
SetEvent(Bad2DoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [BAD2] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (Bad2StatusHandle, &Bad2Status)) {
status = GetLastError();
DbgPrint(" [BAD2] SetServiceStatus error %ld\n",status);
}
CloseHandle(Bad2DoneEvent);
return;
}
/****************************************************************************/
//
// Bad3 will send only its first START_PENDING status, and then it won't send
// any further status messages for any reason. Aside from not sending any
// status messages, the service operates normally.
//
DWORD
Bad3Start (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [BAD3] Inside the Bad3 Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [BAD3] CommandArg%d = %s\n", i,argv[i]);
}
Bad3DoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
Bad3Status.dwServiceType = SERVICE_WIN32;
Bad3Status.dwCurrentState = SERVICE_START_PENDING;
Bad3Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
Bad3Status.dwWin32ExitCode = 0;
Bad3Status.dwServiceSpecificExitCode = 0;
Bad3Status.dwCheckPoint = 1;
Bad3Status.dwWaitHint = 5000;
//
// Register the Control Handler routine.
//
DbgPrint(" [BAD3] Getting Ready to call RegisterServiceCtrlHandler\n");
Bad3StatusHandle = RegisterServiceCtrlHandler(
TEXT("Bad3"),
Bad3CtrlHandler);
if (Bad3StatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [BAD3] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (Bad3StatusHandle, &Bad3Status)) {
status = GetLastError();
DbgPrint(" [BAD3] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
Bad3DoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [BAD3] Leaving the Bad3 service\n");
CloseHandle(Bad3DoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
Bad3CtrlHandler (
IN DWORD Opcode
)
{
DbgPrint(" [BAD3] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
Bad3Status.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
Bad3Status.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
Bad3Status.dwWin32ExitCode = 0;
Bad3Status.dwServiceSpecificExitCode = 0;
Bad3Status.dwCurrentState = SERVICE_STOPPED;
Bad3Status.dwCheckPoint = 1;
Bad3Status.dwWaitHint = 20000;
SetEvent(Bad3DoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [BAD3] Unrecognized opcode %ld\n", Opcode);
}
//
// Don't send a status response.
//
#ifdef REMOVE
if (!SetServiceStatus (Bad3StatusHandle, &Bad3Status)) {
status = GetLastError();
DbgPrint(" [BAD3] SetServiceStatus error %ld\n",status);
}
#endif
CloseHandle(Bad3DoneEvent);
return;
}
/****************************************************************************/
//
// Bad4 will start normally, but on stop it only sends one stop pending
// status before it terminates itself without further notification.
//
DWORD
Bad4Start (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [BAD4] Inside the Bad4 Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [BAD4] CommandArg%d = %s\n", i,argv[i]);
}
Bad4DoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
Bad4Status.dwServiceType = SERVICE_WIN32;
Bad4Status.dwCurrentState = SERVICE_RUNNING;
Bad4Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
Bad4Status.dwWin32ExitCode = 0;
Bad4Status.dwServiceSpecificExitCode = 0;
Bad4Status.dwCheckPoint = 0;
Bad4Status.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [BAD4] Getting Ready to call RegisterServiceCtrlHandler\n");
Bad4StatusHandle = RegisterServiceCtrlHandler(
TEXT("Bad4"),
Bad4CtrlHandler);
if (Bad4StatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [BAD4] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (Bad4StatusHandle, &Bad4Status)) {
status = GetLastError();
DbgPrint(" [BAD4] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
Bad4DoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [BAD4] Leaving the Bad4 service\n");
CloseHandle(Bad4DoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
Bad4CtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [BAD4] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
Bad4Status.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
Bad4Status.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
Bad4Status.dwWin32ExitCode = 0;
Bad4Status.dwServiceSpecificExitCode = 0;
Bad4Status.dwCurrentState = SERVICE_STOP_PENDING;
Bad4Status.dwCheckPoint = 1;
Bad4Status.dwWaitHint = 20000;
SetEvent(Bad4DoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [BAD4] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (Bad4StatusHandle, &Bad4Status)) {
status = GetLastError();
DbgPrint(" [BAD4] SetServiceStatus error %ld\n",status);
}
CloseHandle(Bad4DoneEvent);
return;
}
/****************************************************************************/
//
// HangOnStop Service doesn't return from the control handling routine
// on STOP requests until after the pipe timeout period (30 seconds).
// After 40 seconds, it sends a STOP_PENDING status.
//
// Just to confuse things, after the timeout, this service sends a
// RUNNING status (after an additional 30msec delay). Then it sleeps for
// 20 seconds before sending a STOPPED status.
//
DWORD
HangOnStopStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DbgPrint(" [HangOnStop] Inside the HangOnStop Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [HangOnStop] CommandArg%d = %s\n", i,argv[i]);
}
HangOnStopDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
HangOnStopStatus.dwServiceType = SERVICE_WIN32;
HangOnStopStatus.dwCurrentState = SERVICE_RUNNING;
HangOnStopStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
HangOnStopStatus.dwWin32ExitCode = 0;
HangOnStopStatus.dwServiceSpecificExitCode = 0;
HangOnStopStatus.dwCheckPoint = 0;
HangOnStopStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [HangOnStop] Getting Ready to call RegisterServiceCtrlHandler\n");
HangOnStopStatusHandle = RegisterServiceCtrlHandler(
TEXT("HangOnStop"),
HangOnStopCtrlHandler);
if (HangOnStopStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [HangOnStop] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (HangOnStopStatusHandle, &HangOnStopStatus)) {
status = GetLastError();
DbgPrint(" [HangOnStop] SetServiceStatus error %ld\n",status);
}
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
HangOnStopDoneEvent,
INFINITE_WAIT_TIME);
Sleep(30);
HangOnStopStatus.dwCurrentState = SERVICE_RUNNING;
if (!SetServiceStatus (HangOnStopStatusHandle, &HangOnStopStatus)) {
status = GetLastError();
DbgPrint(" [HangOnStop] SetServiceStatus error %ld\n",status);
}
Sleep(20000);
HangOnStopStatus.dwCurrentState = SERVICE_STOPPED;
if (!SetServiceStatus (HangOnStopStatusHandle, &HangOnStopStatus)) {
status = GetLastError();
DbgPrint(" [HangOnStop] SetServiceStatus error %ld\n",status);
}
DbgPrint(" [HangOnStop] Leaving the HangOnStop service\n");
CloseHandle(HangOnStopDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
HangOnStopCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [HangOnStop] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
HangOnStopStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
HangOnStopStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_STOP:
HangOnStopStatus.dwWin32ExitCode = 0;
HangOnStopStatus.dwServiceSpecificExitCode = 0;
HangOnStopStatus.dwCurrentState = SERVICE_STOP_PENDING;
HangOnStopStatus.dwCheckPoint = 1;
HangOnStopStatus.dwWaitHint = 20000;
Sleep(40000);
SetEvent(HangOnStopDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [HangOnStop] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (HangOnStopStatusHandle, &HangOnStopStatus)) {
status = GetLastError();
DbgPrint(" [HangOnStop] SetServiceStatus error %ld\n",status);
}
CloseHandle(HangOnStopDoneEvent);
return;
}
/****************************************************************************/
DWORD
StartProcStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
STARTUPINFOW ScStartupInfo;
PROCESS_INFORMATION processInfo;
LPWSTR ImageName;
HWND hWnd= NULL;
DbgPrint(" [START_PROC] Inside the StartProc Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [START_PROC] CommandArg%d = %s\n", i,argv[i]);
}
//
// This call to a GDI function causes a connection to the Win
// User Server. It doesn't matter which GDI function is called, this
// one happens to be easiest. This allows us to create a child process
// that is interactive with the user (like cmd.exe).
//
hWnd = GetDesktopWindow();
if (hWnd == NULL) {
DbgPrint(" [START_PROC] GetDesktopWindow call failed %d\n", GetLastError());
}
//
// Create an event to wait on.
//
StartProcDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
StartProcStatus.dwServiceType = SERVICE_WIN32;
StartProcStatus.dwCurrentState = SERVICE_RUNNING;
StartProcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;
StartProcStatus.dwWin32ExitCode = 0;
StartProcStatus.dwServiceSpecificExitCode = 0;
StartProcStatus.dwCheckPoint = 0;
StartProcStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
DbgPrint(" [START_PROC] Getting Ready to call RegisterServiceCtrlHandler\n");
StartProcStatusHandle = RegisterServiceCtrlHandler(
TEXT("StartProc"),
StartProcCtrlHandler);
if (StartProcStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [START_PROC] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (StartProcStatusHandle, &StartProcStatus)) {
status = GetLastError();
DbgPrint(" [START_PROC] SetServiceStatus error %ld\n",status);
}
//*******************************************************************
// Start a Child Process
//
ScStartupInfo.cb = sizeof(STARTUPINFOW); // size
ScStartupInfo.lpReserved = NULL; // lpReserved
ScStartupInfo.lpDesktop = NULL; // DeskTop
ScStartupInfo.lpTitle = L"Local System Window"; // Title
ScStartupInfo.dwX = 0; // X (position)
ScStartupInfo.dwY = 0; // Y (position)
ScStartupInfo.dwXSize = 0; // XSize (dimension)
ScStartupInfo.dwYSize = 0; // YSize (dimension)
ScStartupInfo.dwXCountChars = 0; // XCountChars
ScStartupInfo.dwYCountChars = 0; // YCountChars
ScStartupInfo.dwFillAttribute = 0; // FillAttributes
ScStartupInfo.dwFlags = STARTF_FORCEOFFFEEDBACK;
// Flags - should be STARTF_TASKNOTCLOSABLE
ScStartupInfo.wShowWindow = SW_SHOWNORMAL; // ShowWindow
ScStartupInfo.cbReserved2 = 0L; // cbReserved
ScStartupInfo.lpReserved2 = NULL; // lpReserved
// ScStartupInfo.dwFlags |= STARTF_DESKTOPINHERIT;
// ScStartupInfo.lpDesktop = pszInteractiveDesktop;
ImageName = L"cmd.exe";
if (!CreateProcessW (
NULL, // Fully qualified image name
ImageName, // Command Line
NULL, // Process Attributes
NULL, // Thread Attributes
TRUE, // Inherit Handles
CREATE_NEW_CONSOLE, // Creation Flags
NULL, // Pointer to Environment block
NULL, // Pointer to Current Directory
&ScStartupInfo, // Startup Info
&processInfo) // ProcessInformation
) {
status = GetLastError();
DbgPrint(" [START_PROC] CreateProcess %ws failed %d \n",
ImageName,
status);
}
else {
DbgPrint(" [START_PROC]CreateProcess Success \n");
}
//
//
//*******************************************************************
//
// Wait forever until we are told to terminate.
//
status = WaitForSingleObject (
StartProcDoneEvent,
INFINITE_WAIT_TIME);
DbgPrint(" [START_PROC] Leaving the StartProc service\n");
CloseHandle(StartProcDoneEvent);
CloseHandle(hWnd);
return(NO_ERROR);
}
/****************************************************************************/
VOID
StartProcCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [START_PROC] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
StartProcStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
StartProcStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
StartProcStatus.dwWin32ExitCode = 0;
StartProcStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(StartProcDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
DbgPrint(" [START_PROC] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (StartProcStatusHandle, &StartProcStatus)) {
status = GetLastError();
DbgPrint(" [START_PROC] SetServiceStatus error %ld\n",status);
}
return;
}
/****************************************************************************/
DWORD
StartAndDieStart (
DWORD argc,
LPTSTR *argv
)
{
DWORD status;
DWORD i;
DWORD checkpoint=1;
DbgPrint(" [StartAndDie] Inside the StartAndDie Service Thread\n");
for (i=0; i<argc; i++) {
DbgPrint(" [START&DIE] CommandArg%d = %s\n", i,argv[i]);
}
StartAndDieDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
//
// Fill in this services status structure
//
StartAndDieStatus.dwServiceType = SERVICE_WIN32;
StartAndDieStatus.dwCurrentState = SERVICE_START_PENDING;
StartAndDieStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;
StartAndDieStatus.dwWin32ExitCode = 0;
StartAndDieStatus.dwServiceSpecificExitCode = 0;
StartAndDieStatus.dwCheckPoint = checkpoint++;
StartAndDieStatus.dwWaitHint = 40000;
//
// Register the Control Handler routine.
//
DbgPrint(" [START&DIE] Getting Ready to call RegisterServiceCtrlHandler\n");
StartAndDieStatusHandle = RegisterServiceCtrlHandler(
TEXT("StartAndDie"),
StartAndDieCtrlHandler);
if (StartAndDieStatusHandle == (SERVICE_STATUS_HANDLE)0) {
DbgPrint(" [START&DIE] RegisterServiceCtrlHandler failed %d\n", GetLastError());
}
//
// Return the status
//
if (!SetServiceStatus (StartAndDieStatusHandle, &StartAndDieStatus)) {
status = GetLastError();
DbgPrint(" [START&DIE] SetServiceStatus error %ld\n",status);
}
//
// Sleep for a bit, the say we are running, then say we are stopped.
//
Sleep(30000);
StartAndDieStatus.dwCurrentState = SERVICE_RUNNING;
StartAndDieStatus.dwCheckPoint = 0;
StartAndDieStatus.dwWaitHint = 0;
if (!SetServiceStatus (StartAndDieStatusHandle, &StartAndDieStatus)) {
status = GetLastError();
DbgPrint("[START&DIE] SetServiceStatus error %ld\n",status);
}
StartAndDieStatus.dwCurrentState = SERVICE_STOPPED;
StartAndDieStatus.dwCheckPoint = 0;
StartAndDieStatus.dwWaitHint = 0;
StartAndDieStatus.dwWin32ExitCode = ERROR_INVALID_ENVIRONMENT;
if (!SetServiceStatus (StartAndDieStatusHandle, &StartAndDieStatus)) {
status = GetLastError();
DbgPrint("[START&DIE] SetServiceStatus error %ld\n",status);
}
DbgPrint(" [START&DIE] Leaving the start&die service\n");
CloseHandle(StartAndDieDoneEvent);
return(NO_ERROR);
}
/****************************************************************************/
VOID
StartAndDieCtrlHandler (
IN DWORD Opcode
)
{
DWORD status;
DbgPrint(" [START&DIE] opcode = %ld\n", Opcode);
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
SvcPrintf("StartAndDie received a PAUSE\n");
StartAndDieStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
SvcPrintf("StartAndDie received a CONTINUE\n");
StartAndDieStatus.dwCurrentState = SERVICE_RUNNING;
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
SvcPrintf("StartAndDie received a STOP\n");
StartAndDieStatus.dwWin32ExitCode = 0;
StartAndDieStatus.dwCurrentState = SERVICE_STOPPED;
SetEvent(StartAndDieDoneEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
SvcPrintf("StartAndDie received an INTERROGATE\n");
break;
default:
DbgPrint(" [START&DIE] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (StartAndDieStatusHandle, &StartAndDieStatus)) {
status = GetLastError();
DbgPrint(" [START&DIE] SetServiceStatus error %ld\n",status);
}
return;
}
VOID
SetUpConsole()
{
//#ifdef NOT_NECESSARY
CONSOLE_SCREEN_BUFFER_INFO csbi;
COORD coord;
HANDLE consoleHandle=NULL;
if (!AllocConsole()) {
DbgPrint("[TS2]AllocConsole failed %d\n",GetLastError());
}
consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (consoleHandle == NULL) {
DbgPrint("[TS2]GetStdHandle failed %d\n",GetLastError());
}
if (!GetConsoleScreenBufferInfo(
GetStdHandle(STD_OUTPUT_HANDLE),
&csbi)) {
DbgPrint("[TS2]GetConsoleScreenBufferInfo failed %d\n",GetLastError());
}
coord.X = (SHORT)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
coord.Y = (SHORT)((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) * 20);
if (!SetConsoleScreenBufferSize(
GetStdHandle(STD_OUTPUT_HANDLE),
coord)) {
DbgPrint("[TS2]SetConsoleScreenBufferSize failed %d\n",GetLastError());
}
//#endif //NOT_NECESSARY
DbgLogFileHandle = CreateFile("\\trace.log",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
0,
NULL);
}
VOID
SvcPrintf (
char *Format,
...
)
/*++
Routine Description:
This routine provides printf functionality when the service is run with
REMOTE.EXE.
sc config LUMPY binpath= "remote /s \"ts2\" LUMPY"
NOTE: It is not necessary to allocate a console in this case because
remote already provides one. So the only portion of SetupConsole() that
is used is the portion the opens the debug dump file.
Arguments:
Same as printf
Return Value:
--*/
{
va_list arglist;
char OutputBuffer[1024];
ULONG length;
va_start( arglist, Format );
vsprintf( OutputBuffer, Format, arglist );
va_end( arglist );
length = strlen( OutputBuffer );
if (!WriteFile(
GetStdHandle(STD_OUTPUT_HANDLE),
(LPVOID )OutputBuffer,
length,
&length,
NULL )) {
DbgPrint("[TS2]WriteFile Failed %d \n",GetLastError());
}
if(DbgLogFileHandle != INVALID_HANDLE_VALUE) {
if (!WriteFile(
DbgLogFileHandle,
(LPVOID )OutputBuffer,
length,
&length,
NULL )) {
DbgPrint("[TS2]WriteFile Failed %d \n",GetLastError());
}
}
} // SsPrintf