190 lines
6.6 KiB
C++
190 lines
6.6 KiB
C++
/// \brief To create a basic Windows Service in C++.
|
|
/// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
|
|
|
|
#include <Windows.h>
|
|
#include <tchar.h>
|
|
#include <string>
|
|
|
|
#include "libipc/ipc.h"
|
|
|
|
SERVICE_STATUS g_ServiceStatus = {0};
|
|
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
|
|
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
|
|
|
|
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv);
|
|
VOID WINAPI ServiceCtrlHandler (DWORD);
|
|
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);
|
|
|
|
#define SERVICE_NAME _T("My Sample Service")
|
|
|
|
int _tmain (int argc, TCHAR *argv[]) {
|
|
OutputDebugString(_T("My Sample Service: Main: Entry"));
|
|
|
|
SERVICE_TABLE_ENTRY ServiceTable[] = {
|
|
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE) {
|
|
OutputDebugString(_T("My Sample Service: Main: StartServiceCtrlDispatcher returned error"));
|
|
return GetLastError ();
|
|
}
|
|
|
|
OutputDebugString(_T("My Sample Service: Main: Exit"));
|
|
return 0;
|
|
}
|
|
|
|
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) {
|
|
DWORD Status = E_FAIL;
|
|
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: Entry"));
|
|
|
|
g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);
|
|
|
|
if (g_StatusHandle == NULL) {
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: RegisterServiceCtrlHandler returned error"));
|
|
goto EXIT;
|
|
}
|
|
|
|
// Tell the service controller we are starting
|
|
ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
|
|
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
g_ServiceStatus.dwControlsAccepted = 0;
|
|
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
g_ServiceStatus.dwWin32ExitCode = 0;
|
|
g_ServiceStatus.dwServiceSpecificExitCode = 0;
|
|
g_ServiceStatus.dwCheckPoint = 0;
|
|
|
|
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
|
}
|
|
|
|
/*
|
|
* Perform tasks neccesary to start the service here
|
|
*/
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: Performing Service Start Operations"));
|
|
|
|
// Create stop event to wait on later.
|
|
g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
if (g_ServiceStopEvent == NULL) {
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error"));
|
|
|
|
g_ServiceStatus.dwControlsAccepted = 0;
|
|
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|
g_ServiceStatus.dwWin32ExitCode = GetLastError();
|
|
g_ServiceStatus.dwCheckPoint = 1;
|
|
|
|
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
|
}
|
|
goto EXIT;
|
|
}
|
|
|
|
// Tell the service controller we are started
|
|
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
g_ServiceStatus.dwWin32ExitCode = 0;
|
|
g_ServiceStatus.dwCheckPoint = 0;
|
|
|
|
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
|
}
|
|
|
|
// Start the thread that will perform the main task of the service
|
|
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
|
|
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: Waiting for Worker Thread to complete"));
|
|
|
|
// Wait until our worker thread exits effectively signaling that the service needs to stop
|
|
WaitForSingleObject (hThread, INFINITE);
|
|
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: Worker Thread Stop Event signaled"));
|
|
|
|
|
|
/*
|
|
* Perform any cleanup tasks
|
|
*/
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: Performing Cleanup Operations"));
|
|
|
|
CloseHandle (g_ServiceStopEvent);
|
|
|
|
g_ServiceStatus.dwControlsAccepted = 0;
|
|
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|
g_ServiceStatus.dwWin32ExitCode = 0;
|
|
g_ServiceStatus.dwCheckPoint = 3;
|
|
|
|
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
|
}
|
|
|
|
EXIT:
|
|
OutputDebugString(_T("My Sample Service: ServiceMain: Exit"));
|
|
return;
|
|
}
|
|
|
|
VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) {
|
|
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Entry"));
|
|
|
|
switch (CtrlCode) {
|
|
case SERVICE_CONTROL_STOP :
|
|
|
|
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SERVICE_CONTROL_STOP Request"));
|
|
|
|
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
|
|
break;
|
|
|
|
/*
|
|
* Perform tasks neccesary to stop the service here
|
|
*/
|
|
|
|
g_ServiceStatus.dwControlsAccepted = 0;
|
|
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
g_ServiceStatus.dwWin32ExitCode = 0;
|
|
g_ServiceStatus.dwCheckPoint = 4;
|
|
|
|
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
|
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
|
|
}
|
|
|
|
// This will signal the worker thread to start shutting down
|
|
SetEvent (g_ServiceStopEvent);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Exit"));
|
|
}
|
|
|
|
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam) {
|
|
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));
|
|
ipc::channel ipc_r{ipc::prefix{"Global\\"}, "service ipc r", ipc::sender};
|
|
ipc::channel ipc_w{ipc::prefix{"Global\\"}, "service ipc w", ipc::receiver};
|
|
|
|
// Periodically check if the service has been requested to stop
|
|
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
|
|
/*
|
|
* Perform main service function here
|
|
*/
|
|
if (!ipc_r.send("Hello, World!")) {
|
|
OutputDebugString(_T("My Sample Service: send failed."));
|
|
}
|
|
else {
|
|
OutputDebugString(_T("My Sample Service: send [Hello, World!]"));
|
|
auto msg = ipc_w.recv(1000);
|
|
if (msg.empty()) {
|
|
OutputDebugString(_T("My Sample Service: recv error"));
|
|
} else {
|
|
OutputDebugStringA((std::string{"My Sample Service: recv ["} + msg.get<char const *>() + "]").c_str());
|
|
}
|
|
}
|
|
Sleep(3000);
|
|
}
|
|
|
|
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|