19 template <auto UniversalMain>
22 SERVICE_TABLE_ENTRY ServiceTable[] =
24 { g_ServiceName, (LPSERVICE_MAIN_FUNCTION)serviceMain<UniversalMain> },
28 if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
30 throw std::system_error(GetLastError(), std::system_category());
39 static void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
41 SERVICE_STATUS serviceStatus = {};
42 serviceStatus.dwCheckPoint = 0;
43 serviceStatus.dwControlsAccepted = acceptedControls;
44 serviceStatus.dwCurrentState = newState;
45 serviceStatus.dwServiceSpecificExitCode = 0;
46 serviceStatus.dwServiceType = SERVICE_WIN32;
47 serviceStatus.dwWaitHint = 0;
48 serviceStatus.dwWin32ExitCode = exitCode;
50 if (SetServiceStatus(g_StatusHandle, &serviceStatus) == FALSE)
52 LOGERROR(
"SetServiceStatus() failed\n");
57 static void WINAPI serviceCtrlHandler(DWORD CtrlCode)
59 if (CtrlCode == SERVICE_CONTROL_STOP)
62 serviceSetState(0, SERVICE_STOP_PENDING, 0);
67 template <auto MainFunction>
68 static void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
70 wchar_t applicationFilename[MAX_PATH];
71 wchar_t applicationDirectory[MAX_PATH];
74 if (GetModuleFileName(
nullptr, applicationFilename, std::size(applicationFilename)) == 0)
76 serviceSetState(0, SERVICE_STOPPED, GetLastError());
80 const auto LastComponent = std::wcsrchr(applicationFilename, L
'\\');
81 if (LastComponent ==
nullptr)
83 serviceSetState(0, SERVICE_STOPPED, E_UNEXPECTED);
87 const auto LengthToLastComponent = LastComponent - applicationFilename;
90 std::wcsncpy(applicationDirectory, applicationFilename, LengthToLastComponent);
91 applicationDirectory[LengthToLastComponent] = L
'\0';
95 if (SetCurrentDirectory(applicationDirectory) == FALSE)
97 serviceSetState(0, SERVICE_STOPPED, GetLastError());
102 g_StatusHandle = RegisterServiceCtrlHandler(g_ServiceName, serviceCtrlHandler);
103 if (g_StatusHandle ==
nullptr)
105 OutputDebugStringA(
"RegisterServiceCtrlHandler() failed\n");
106 serviceSetState(0, SERVICE_STOPPED, GetLastError());
110 serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0);
112 char MultibyteArgV0[MAX_PATH];
113 char * MultibyteArgV[] = { MultibyteArgV0 };
115 const auto OutputSize = std::size(MultibyteArgV0);
116 const auto TranslateResult = std::wcstombs(MultibyteArgV0, argv[0], OutputSize);
118 if (TranslateResult ==
static_cast<size_t>(-1))
121 MultibyteArgV0[0] =
'\0';
123 else if (TranslateResult == OutputSize)
126 MultibyteArgV0[OutputSize - 1] =
'\0';
129 const auto Result = MainFunction(1, MultibyteArgV,
true);
130 const auto Return = (Result == EXIT_SUCCESS) ? S_OK : E_FAIL;
132 serviceSetState(0, SERVICE_STOPPED, Return);
135 static inline SERVICE_STATUS_HANDLE g_StatusHandle =
nullptr;
136 static inline HANDLE g_ServiceThread = INVALID_HANDLE_VALUE;
137 static inline wchar_t g_ServiceName[] = L
"Cuberite";
153 throw std::system_error(errno, std::system_category());
164 close(STDOUT_FILENO);
165 close(STDERR_FILENO);
void LOGERROR(std::string_view a_Format, const Args &... args)
static bool MakeIntoService()
Make a UNIX daemon.