mirror of https://github.com/tongzx/nt5src
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
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
|
|
|