+ /* lpDependencies is doubly NULL terminated. */\r
+ while (qsc->lpDependencies[*bufsize]) {\r
+ while (qsc->lpDependencies[*bufsize]) ++*bufsize;\r
+ ++*bufsize;\r
+ }\r
+\r
+ *bufsize += 2;\r
+\r
+ *buffer = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *bufsize * sizeof(TCHAR));\r
+ if (! *buffer) {\r
+ *bufsize = 0;\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("lpDependencies"), _T("get_service_dependencies()"));\r
+ HeapFree(GetProcessHeap(), 0, qsc);\r
+ return 4;\r
+ }\r
+\r
+ if (type == DEPENDENCY_ALL) memmove(*buffer, qsc->lpDependencies, *bufsize * sizeof(TCHAR));\r
+ else {\r
+ TCHAR *s;\r
+ size_t i = 0;\r
+ *bufsize = 0;\r
+ for (s = qsc->lpDependencies; *s; s++) {\r
+ /* Only copy the appropriate type of dependency. */\r
+ if ((*s == SC_GROUP_IDENTIFIER && type & DEPENDENCY_GROUPS) || (*s != SC_GROUP_IDENTIFIER && type & DEPENDENCY_SERVICES)) {\r
+ size_t len = _tcslen(s) + 1;\r
+ *bufsize += (unsigned long) len;\r
+ memmove(*buffer + i, s, len * sizeof(TCHAR));\r
+ i += len;\r
+ }\r
+\r
+ while (*s) s++;\r
+ }\r
+ ++*bufsize;\r
+ }\r
+\r
+ HeapFree(GetProcessHeap(), 0, qsc);\r
+\r
+ if (! *buffer[0]) {\r
+ HeapFree(GetProcessHeap(), 0, *buffer);\r
+ *buffer = 0;\r
+ *bufsize = 0;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int get_service_dependencies(const TCHAR *service_name, SC_HANDLE service_handle, TCHAR **buffer, unsigned long *bufsize) {\r
+ return get_service_dependencies(service_name, service_handle, buffer, bufsize, DEPENDENCY_ALL);\r
+}\r
+\r
+int set_service_description(const TCHAR *service_name, SC_HANDLE service_handle, TCHAR *buffer) {\r
+ SERVICE_DESCRIPTION description;\r
+ ZeroMemory(&description, sizeof(description));\r
+ /*\r
+ lpDescription must be NULL if we aren't changing, the new description\r
+ or "".\r
+ */\r
+ if (buffer && buffer[0]) description.lpDescription = buffer;\r
+ else description.lpDescription = _T("");\r
+\r
+ if (ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DESCRIPTION, &description)) return 0;\r
+\r
+ log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DESCRIPTION_FAILED, service_name, error_string(GetLastError()), 0);\r
+ return 1;\r
+}\r
+\r
+int get_service_description(const TCHAR *service_name, SC_HANDLE service_handle, unsigned long len, TCHAR *buffer) {\r
+ if (! buffer) return 1;\r
+\r
+ unsigned long bufsize;\r
+ QueryServiceConfig2(service_handle, SERVICE_CONFIG_DESCRIPTION, 0, 0, &bufsize);\r
+ unsigned long error = GetLastError();\r
+ if (error == ERROR_INSUFFICIENT_BUFFER) {\r
+ SERVICE_DESCRIPTION *description = (SERVICE_DESCRIPTION *) HeapAlloc(GetProcessHeap(), 0, bufsize);\r
+ if (! description) {\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("SERVICE_CONFIG_DESCRIPTION"), _T("get_service_description()"));\r
+ return 2;\r
+ }\r
+\r
+ if (QueryServiceConfig2(service_handle, SERVICE_CONFIG_DESCRIPTION, (unsigned char *) description, bufsize, &bufsize)) {\r
+ if (description->lpDescription) _sntprintf_s(buffer, len, _TRUNCATE, _T("%s"), description->lpDescription);\r
+ else ZeroMemory(buffer, len * sizeof(TCHAR));\r
+ HeapFree(GetProcessHeap(), 0, description);\r
+ return 0;\r
+ }\r
+ else {\r
+ HeapFree(GetProcessHeap(), 0, description);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_CONFIG_DESCRIPTION"), error_string(error));\r
+ return 3;\r
+ }\r
+ }\r
+ else {\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_CONFIG_DESCRIPTION"), error_string(error));\r
+ return 4;\r
+ }\r
+}\r
+\r
+int get_service_startup(const TCHAR *service_name, SC_HANDLE service_handle, const QUERY_SERVICE_CONFIG *qsc, unsigned long *startup) {\r
+ if (! qsc) return 1;\r
+\r
+ switch (qsc->dwStartType) {\r
+ case SERVICE_DEMAND_START: *startup = NSSM_STARTUP_MANUAL; break;\r
+ case SERVICE_DISABLED: *startup = NSSM_STARTUP_DISABLED; break;\r
+ default: *startup = NSSM_STARTUP_AUTOMATIC;\r
+ }\r
+\r
+ if (*startup != NSSM_STARTUP_AUTOMATIC) return 0;\r
+\r
+ /* Check for delayed start. */\r
+ unsigned long bufsize;\r
+ unsigned long error;\r
+ QueryServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, 0, 0, &bufsize);\r
+ error = GetLastError();\r
+ if (error == ERROR_INSUFFICIENT_BUFFER) {\r
+ SERVICE_DELAYED_AUTO_START_INFO *info = (SERVICE_DELAYED_AUTO_START_INFO *) HeapAlloc(GetProcessHeap(), 0, bufsize);\r
+ if (! info) {\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("SERVICE_DELAYED_AUTO_START_INFO"), _T("get_service_startup()"));\r
+ return 2;\r
+ }\r
+\r
+ if (QueryServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (unsigned char *) info, bufsize, &bufsize)) {\r
+ if (info->fDelayedAutostart) *startup = NSSM_STARTUP_DELAYED;\r
+ HeapFree(GetProcessHeap(), 0, info);\r
+ return 0;\r
+ }\r
+ else {\r
+ error = GetLastError();\r
+ if (error != ERROR_INVALID_LEVEL) {\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error));\r
+ return 3;\r
+ }\r
+ }\r
+ }\r
+ else if (error != ERROR_INVALID_LEVEL) {\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_DELAYED_AUTO_START_INFO"), error_string(error));\r
+ return 3;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int get_service_username(const TCHAR *service_name, const QUERY_SERVICE_CONFIG *qsc, TCHAR **username, size_t *usernamelen) {\r
+ if (! username) return 1;\r
+ if (! usernamelen) return 1;\r
+\r
+ *username = 0;\r
+ *usernamelen = 0;\r
+\r
+ if (! qsc) return 1;\r
+\r
+ if (qsc->lpServiceStartName[0]) {\r
+ if (is_localsystem(qsc->lpServiceStartName)) return 0;\r
+\r
+ size_t len = _tcslen(qsc->lpServiceStartName);\r
+ *username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(TCHAR));\r
+ if (! *username) {\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("username"), _T("get_service_username()"));\r
+ return 2;\r
+ }\r
+\r
+ memmove(*username, qsc->lpServiceStartName, (len + 1) * sizeof(TCHAR));\r
+ *usernamelen = len;\r