#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
HANDLE hStopEvent;
HANDLE hThreads[3] = {NULL,NULL,NULL};
LPTSTR lpszServiceName;
SERVICE_STATUS_HANDLE ssh;
DWORD WINAPI ThreadProc(LPVOID lpParameter);
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);
void WINAPI Service_Ctrl(DWORD dwCtrlCode);
void ErrorStopService(LPTSTR lpszAPI);
void SetTheServiceStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,
DWORD dwCheckPoint, DWORD dwWaitHint);
// Entry point for service. Calls StartServiceCtrlDispatcher
// and then blocks until the ServiceMain function returns.
void _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ste[] =
{{TEXT(""),(LPSERVICE_MAIN_FUNCTION)Service_Main}, {NULL,NULL}};
OutputDebugString(TEXT("Entered service code\n"));
if (!StartServiceCtrlDispatcher(ste))
{
TCHAR error[256];
StringCchPrintf(error,
256,
TEXT("Error code for StartServiceCtrlDispatcher: %u.\n"),
GetLastError());
OutputDebugString(error);
}
else
OutputDebugString(TEXT("StartServiceCtrlDispatcher OK\n"));
}
// Called by the service control manager after the call to
// StartServiceCtrlDispatcher.
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
DWORD ThreadId;
DWORD t;
DWORD dwWaitRes;
// Obtain the name of the service.
lpszServiceName = lpszArgv[0];
// Register the service ctrl handler.
ssh = RegisterServiceCtrlHandler(lpszServiceName,
(LPHANDLER_FUNCTION)Service_Ctrl);
// Create the event to signal the service to stop.
hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hStopEvent == NULL)
ErrorStopService(TEXT("CreateEvent"));
//
// Insert one-time work that you want to complete before starting.
//
for (t=0;t<3;t++)
{
hThreads[t] = CreateThread(NULL,0,ThreadProc,
(LPVOID)t,0,&ThreadId);
if (hThreads[t] == INVALID_HANDLE_VALUE)
ErrorStopService(TEXT("CreateThread"));
}
// The service has started.
SetTheServiceStatus(SERVICE_RUNNING, 0, 0, 0);
OutputDebugString(TEXT("SetTheServiceStatus, SERVICE_RUNNING\n"));
//
// Main loop for the service.
//
while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0)
{
/***************************************************************/
// Main loop for service.
/***************************************************************/
}
// Wait for threads to exit.
for (t=1;TRUE;t++)
{
if ((dwWaitRes = WaitForMultipleObjects(3,hThreads,TRUE,1000))
== WAIT_OBJECT_0)
break;
else if((dwWaitRes == WAIT_FAILED)||(dwWaitRes==WAIT_ABANDONED))
ErrorStopService(TEXT("WaitForMultipleObjects"));
else
SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
}
// Close the event handle and the thread handle.
if (!CloseHandle(hStopEvent))
ErrorStopService(TEXT("CloseHandle"));
if (!CloseHandle(hThreads[0]))
ErrorStopService(TEXT("CloseHandle"));
if (!CloseHandle(hThreads[1]))
ErrorStopService(TEXT("CloseHandle"));
if (!CloseHandle(hThreads[2]))
ErrorStopService(TEXT("CloseHandle"));
// Stop the service.
OutputDebugString(TEXT("SetTheServiceStatus, SERVICE_STOPPED\n"));
SetTheServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
}
// Handles control signals from the service control manager.
void WINAPI Service_Ctrl(DWORD dwCtrlCode)
{
DWORD dwState = SERVICE_RUNNING;
switch(dwCtrlCode)
{
case SERVICE_CONTROL_STOP:
dwState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_SHUTDOWN:
dwState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
// Set the status of the service.
SetTheServiceStatus(dwState, NO_ERROR, 0, 0);
OutputDebugString(
TEXT("SetTheServiceStatus, Service_Ctrl function\n"));
// Tell service_main thread to stop.
if ((dwCtrlCode == SERVICE_CONTROL_STOP) ||
(dwCtrlCode == SERVICE_CONTROL_SHUTDOWN))
{
if (!SetEvent(hStopEvent))
ErrorStopService(TEXT("SetEvent"));
else
OutputDebugString(TEXT("Signal service_main thread\n"));
}
}
// Thread procedure for all three worker threads.
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
INT nThreadNum = (INT)lpParameter;
TCHAR szOutput[25];
while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0)
{
// Just to have something to do, it will beep every second.
Sleep(1000);
StringCchPrintf(szOutput, 25,
TEXT("\nThread %d says Beep\n"), nThreadNum);
OutputDebugString(szOutput); //Send visual to debugger.
}
return 0;
}
// Wraps SetServiceStatus.
void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
DWORD dwCheckPoint, DWORD dwWaitHint)
{
SERVICE_STATUS ss; // Current status of the service.
// Disable control requests until the service is started.
if (dwCurrentState == SERVICE_START_PENDING)
ss.dwControlsAccepted = 0;
else
ss.dwControlsAccepted =
SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
// TODO: Add any other flags here
// Initialize ss structure.
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwServiceSpecificExitCode = 0;
ss.dwCurrentState = dwCurrentState;
ss.dwWin32ExitCode = dwWin32ExitCode;
ss.dwCheckPoint = dwCheckPoint;
ss.dwWaitHint = dwWaitHint;
// Send status of the service to the Service Controller.
if (!SetServiceStatus(ssh, &ss))
ErrorStopService(TEXT("SetServiceStatus"));
}
// Handle API errors or other problems by ending the service and
// displaying an error message to the debugger.
void ErrorStopService(LPTSTR lpszAPI)
{
INT t;
TCHAR buffer[256] = TEXT("");
TCHAR error[1024] = TEXT("");
LPVOID lpvMessageBuffer;
DWORD dwWaitRes;
StringCchPrintf(buffer,256,TEXT("API = %s, "), lpszAPI);
StringCchCat(error, 1024, buffer);
ZeroMemory(buffer, sizeof(buffer));
StringCchPrintf(buffer, 256,
TEXT("error code = %d, "), GetLastError());
StringCchCat(error, 1024, buffer);
// Obtain the error string.
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
ZeroMemory((LPVOID)buffer, (DWORD)sizeof(buffer));
StringCchPrintf(buffer, 256,
TEXT("message = %s"), (TCHAR *)lpvMessageBuffer);
StringCchCat(error, 1024, buffer);
// Free the buffer allocated by the system.
LocalFree(lpvMessageBuffer);
// Write the error string to the debugger.
OutputDebugString(error);
// If you have threads running, tell them to stop. Something went
// wrong, and you need to stop them so you can inform the SCM.
SetEvent(hStopEvent);
// Wait for the threads to stop.
for (t=1;TRUE;t++)
{
if ((dwWaitRes = WaitForMultipleObjects(3,hThreads,TRUE,1000))
== WAIT_OBJECT_0)
break;
else if ((dwWaitRes == WAIT_FAILED)||
(dwWaitRes == WAIT_ABANDONED))
break; // Our wait failed
else
{
SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
}
}
// Stop the service.
SetTheServiceStatus(SERVICE_STOPPED, GetLastError(), 0, 0);
}