+/* Control a service. */\r
+int control_service(unsigned long control, int argc, TCHAR **argv) {\r
+ if (argc < 1) return usage(1);\r
+ TCHAR *service_name = argv[0];\r
+ TCHAR canonical_name[SERVICE_NAME_LENGTH];\r
+\r
+ SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);\r
+ if (! services) {\r
+ print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
+ return 2;\r
+ }\r
+\r
+ unsigned long access = SERVICE_QUERY_STATUS;\r
+ switch (control) {\r
+ case NSSM_SERVICE_CONTROL_START:\r
+ access |= SERVICE_START;\r
+ break;\r
+\r
+ case SERVICE_CONTROL_CONTINUE:\r
+ case SERVICE_CONTROL_PAUSE:\r
+ access |= SERVICE_PAUSE_CONTINUE;\r
+ break;\r
+\r
+ case SERVICE_CONTROL_STOP:\r
+ access |= SERVICE_STOP;\r
+ break;\r
+\r
+ case NSSM_SERVICE_CONTROL_ROTATE:\r
+ access |= SERVICE_USER_DEFINED_CONTROL;\r
+ break;\r
+ }\r
+\r
+ SC_HANDLE service_handle = open_service(services, service_name, access, canonical_name, _countof(canonical_name));\r
+ if (! service_handle) {\r
+ CloseServiceHandle(services);\r
+ return 3;\r
+ }\r
+\r
+ int ret;\r
+ unsigned long error;\r
+ SERVICE_STATUS service_status;\r
+ if (control == NSSM_SERVICE_CONTROL_START) {\r
+ unsigned long initial_status = SERVICE_STOPPED;\r
+ ret = StartService(service_handle, (unsigned long) argc, (const TCHAR **) argv);\r
+ error = GetLastError();\r
+ CloseServiceHandle(services);\r
+\r
+ if (error == ERROR_IO_PENDING) {\r
+ /*\r
+ Older versions of Windows return immediately with ERROR_IO_PENDING\r
+ indicate that the operation is still in progress. Newer versions\r
+ will return it if there really is a delay.\r
+ */\r
+ ret = 1;\r
+ error = ERROR_SUCCESS;\r
+ }\r
+\r
+ if (ret) {\r
+ int response = await_service_control_response(control, service_handle, &service_status, initial_status);\r
+ CloseServiceHandle(service_handle);\r
+\r
+ if (response) {\r
+ print_message(stderr, NSSM_MESSAGE_BAD_CONTROL_RESPONSE, canonical_name, service_status_text(service_status.dwCurrentState), service_control_text(control));\r
+ return 1;\r
+ }\r
+ else _tprintf(_T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error));\r
+ return 0;\r
+ }\r
+ else {\r
+ CloseServiceHandle(service_handle);\r
+ _ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error));\r
+ return 1;\r
+ }\r
+ }\r
+ else if (control == SERVICE_CONTROL_INTERROGATE) {\r
+ /*\r
+ We could actually send an INTERROGATE control but that won't return\r
+ any information if the service is stopped and we don't care about\r
+ the extra details it might give us in any case. So we'll fake it.\r
+ */\r
+ ret = QueryServiceStatus(service_handle, &service_status);\r
+ error = GetLastError();\r
+\r
+ if (ret) {\r
+ _tprintf(_T("%s\n"), service_status_text(service_status.dwCurrentState));\r
+ return 0;\r
+ }\r
+ else {\r
+ _ftprintf(stderr, _T("%s: %s\n"), canonical_name, error_string(error));\r
+ return 1;\r
+ }\r
+ }\r
+ else {\r
+ ret = ControlService(service_handle, control, &service_status);\r
+ unsigned long initial_status = service_status.dwCurrentState;\r
+ error = GetLastError();\r
+ CloseServiceHandle(services);\r
+\r
+ if (error == ERROR_IO_PENDING) {\r
+ ret = 1;\r
+ error = ERROR_SUCCESS;\r
+ }\r
+\r
+ if (ret) {\r
+ int response = await_service_control_response(control, service_handle, &service_status, initial_status);\r
+ CloseServiceHandle(service_handle);\r
+\r
+ if (response) {\r
+ print_message(stderr, NSSM_MESSAGE_BAD_CONTROL_RESPONSE, canonical_name, service_status_text(service_status.dwCurrentState), service_control_text(control));\r
+ return 1;\r
+ }\r
+ else _tprintf(_T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error));\r
+ return 0;\r
+ }\r
+ else {\r
+ CloseServiceHandle(service_handle);\r
+ _ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error));\r
+ if (error == ERROR_SERVICE_NOT_ACTIVE) {\r
+ if (control == SERVICE_CONTROL_SHUTDOWN || control == SERVICE_CONTROL_STOP) return 0;\r
+ }\r
+ return 1;\r
+ }\r
+ }\r
+}\r
+\r