/// \brief To create a basic Windows Service in C++. /// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus #include #include #include #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() + "]").c_str()); } } Sleep(3000); } OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit")); return ERROR_SUCCESS; }