Since version 2.22, NSSM can rotate existing output files when redirecting I/O.\r
\r
Since version 2.22, NSSM can set service display name, description, startup\r
-type and log on details.\r
+type, log on details and dependencies.\r
\r
Since version 2.22, NSSM can manage existing services.\r
\r
IDLE_PRIORITY_CLASS\r
\r
\r
+The DependOnGroup and DependOnService parameters are used to query or set\r
+the dependencies for the service. When setting dependencies, each service\r
+or service group (preceded with the + symbol) should be specified in\r
+separate command line arguments. For example:\r
+\r
+ nssm set <servicename> DependOnService RpcSs LanmanWorkstation\r
+\r
+\r
The Name parameter can only be queried, not set. It returns the service's\r
registry key name. This may be useful to know if you take advantage of\r
the fact that you can substitute the service's display name anywhere where\r
#include "nssm.h"\r
\r
-static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_LOGON, NSSM_TAB_PROCESS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
+static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_LOGON, NSSM_TAB_DEPENDENCIES, NSSM_TAB_PROCESS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
static HWND tablist[NSSM_NUM_TABS];\r
static int selected_tab;\r
\r
if (service->type & SERVICE_INTERACTIVE_PROCESS) SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_SETCHECK, BST_CHECKED, 0);\r
}\r
\r
+ /* Dependencies tab. */\r
+ if (service->dependencieslen) {\r
+ TCHAR *formatted;\r
+ unsigned long newlen;\r
+ if (format_double_null(service->dependencies, service->dependencieslen, &formatted, &newlen)) {\r
+ popup_message(dlg, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("dependencies"), _T("nssm_dlg()"));\r
+ }\r
+ else {\r
+ SetDlgItemText(tablist[NSSM_TAB_DEPENDENCIES], IDC_DEPENDENCIES, formatted);\r
+ HeapFree(GetProcessHeap(), 0, formatted);\r
+ }\r
+ }\r
+
/* Process tab. */\r
if (service->priority) {\r
int priority = priority_constant_to_index(service->priority);\r
}\r
}\r
\r
+ /* Get dependencies. */\r
+ unsigned long dependencieslen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_DEPENDENCIES], IDC_DEPENDENCIES), WM_GETTEXTLENGTH, 0, 0);\r
+ if (dependencieslen) {\r
+ TCHAR *dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (dependencieslen + 2) * sizeof(TCHAR));\r
+ if (! dependencies) {\r
+ popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("dependencies"), _T("install()"));\r
+ cleanup_nssm_service(service);\r
+ return 6;\r
+ }\r
+\r
+ if (! GetDlgItemText(tablist[NSSM_TAB_DEPENDENCIES], IDC_DEPENDENCIES, dependencies, dependencieslen + 1)) {\r
+ popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DEPENDENCIES);\r
+ HeapFree(GetProcessHeap(), 0, dependencies);\r
+ cleanup_nssm_service(service);\r
+ return 6;\r
+ }\r
+\r
+ if (unformat_double_null(dependencies, dependencieslen, &service->dependencies, &service->dependencieslen)) {\r
+ HeapFree(GetProcessHeap(), 0, dependencies);\r
+ popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("dependencies"), _T("install()"));\r
+ cleanup_nssm_service(service);\r
+ return 6;\r
+ }\r
+\r
+ HeapFree(GetProcessHeap(), 0, dependencies);\r
+ }\r
+\r
/* Remaining tabs are only for services we manage. */\r
if (service->native) return 0;\r
\r
CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
set_logon_enabled(0);\r
\r
+ /* Dependencies tab. */
+ tab.pszText = message_string(NSSM_GUI_TAB_DEPENDENCIES);\r
+ tab.cchTextMax = (int) _tcslen(tab.pszText);\r
+ SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_DEPENDENCIES, (LPARAM) &tab);\r
+ tablist[NSSM_TAB_DEPENDENCIES] = dialog(MAKEINTRESOURCE(IDD_DEPENDENCIES), window, tab_dlg);\r
+ ShowWindow(tablist[NSSM_TAB_DEPENDENCIES], SW_HIDE);\r
+
/* Remaining tabs are only for services we manage. */\r
if (service->native) return 1;\r
\r
#define REGISTRY_H\r
\r
#define NSSM_REGISTRY _T("SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters")\r
+#define NSSM_REGISTRY_GROUPS _T("SYSTEM\\CurrentControlSet\\Control\\ServiceGroupOrder")\r
+#define NSSM_REG_GROUPS _T("List")\r
#define NSSM_REG_EXE _T("Application")\r
#define NSSM_REG_FLAGS _T("AppParameters")\r
#define NSSM_REG_DIR _T("AppDirectory")\r
#define IDD_ENVIRONMENT 112\r
#define IDD_NATIVE 113\r
#define IDD_PROCESS 114\r
+#define IDD_DEPENDENCIES 115\r
#define IDC_PATH 1000\r
#define IDC_TAB1 1001\r
#define IDC_CANCEL 1002\r
#define IDC_AFFINITY_ALL 1043\r
#define IDC_AFFINITY 1044\r
#define IDC_CONSOLE 1045\r
+#define IDC_DEPENDENCIES 1046\r
\r
// Next default values for new objects\r
// \r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
#define _APS_NEXT_RESOURCE_VALUE 115\r
#define _APS_NEXT_COMMAND_VALUE 40001\r
-#define _APS_NEXT_CONTROL_VALUE 1046\r
+#define _APS_NEXT_CONTROL_VALUE 1047\r
#define _APS_NEXT_SYMED_VALUE 101\r
#endif\r
#endif\r
return qsc;\r
}\r
\r
+int set_service_dependencies(const TCHAR *service_name, SC_HANDLE service_handle, TCHAR *buffer) {\r
+ TCHAR *dependencies = _T("");\r
+ unsigned long num_dependencies = 0;\r
+\r
+ if (buffer && buffer[0]) {\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 1;\r
+ }\r
+\r
+ /*\r
+ Count the dependencies then allocate a buffer big enough for their\r
+ canonical names, ie n * SERVICE_NAME_LENGTH.\r
+ */\r
+ TCHAR *s;\r
+ TCHAR *groups = 0;\r
+ for (s = buffer; *s; s++) {\r
+ num_dependencies++;\r
+ if (*s == SC_GROUP_IDENTIFIER) groups = s;\r
+ while (*s) s++;\r
+ }\r
+\r
+ /* At least one dependency is a group so we need to verify them. */\r
+ if (groups) {\r
+ HKEY key;\r
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NSSM_REGISTRY_GROUPS, 0, KEY_READ, &key)) {\r
+ _ftprintf(stderr, _T("%s: %s\n"), NSSM_REGISTRY_GROUPS, error_string(GetLastError()));\r
+ return 2;\r
+ }\r
+\r
+ unsigned long type;\r
+ unsigned long groupslen;\r
+ unsigned long ret = RegQueryValueEx(key, NSSM_REG_GROUPS, 0, &type, NULL, &groupslen);\r
+ if (ret == ERROR_SUCCESS) {\r
+ groups = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, groupslen);\r
+ if (! groups) {\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("groups"), _T("set_service_dependencies()"));\r
+ return 3;\r
+ }\r
+\r
+ ret = RegQueryValueEx(key, NSSM_REG_GROUPS, 0, &type, (unsigned char *) groups, &groupslen);\r
+ if (ret != ERROR_SUCCESS) {\r
+ _ftprintf(stderr, _T("%s\\%s: %s"), NSSM_REGISTRY_GROUPS, NSSM_REG_GROUPS, error_string(GetLastError()));\r
+ HeapFree(GetProcessHeap(), 0, groups);\r
+ RegCloseKey(key);\r
+ return 4;\r
+ }\r
+ }\r
+ else if (ret != ERROR_FILE_NOT_FOUND) {\r
+ _ftprintf(stderr, _T("%s\\%s: %s"), NSSM_REGISTRY_GROUPS, NSSM_REG_GROUPS, error_string(GetLastError()));\r
+ RegCloseKey(key);\r
+ return 4;\r
+ }\r
+\r
+ RegCloseKey(key);\r
+\r
+ }\r
+\r
+ unsigned long dependencieslen = (num_dependencies * SERVICE_NAME_LENGTH) + 2;\r
+ dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dependencieslen * sizeof(TCHAR));\r
+ size_t i = 0;\r
+\r
+ TCHAR dependency[SERVICE_NAME_LENGTH];\r
+ for (s = buffer; *s; s++) {\r
+ /* Group? */\r
+ if (*s == SC_GROUP_IDENTIFIER) {\r
+ TCHAR *group = s + 1;\r
+\r
+ bool ok = false;\r
+ if (*group) {\r
+ for (TCHAR *g = groups; *g; g++) {\r
+ if (str_equiv(g, group)) {\r
+ ok = true;\r
+ /* Set canonical name. */\r
+ memmove(group, g, _tcslen(g) * sizeof(TCHAR));\r
+ break;\r
+ }\r
+\r
+ while (*g) g++;\r
+ }\r
+ }\r
+\r
+ if (ok) _sntprintf_s(dependency, _countof(dependency), _TRUNCATE, _T("%s"), s);\r
+ else {\r
+ HeapFree(GetProcessHeap(), 0, dependencies);\r
+ if (groups) HeapFree(GetProcessHeap(), 0, groups);\r
+ _ftprintf(stderr, _T("%s: %s"), s, error_string(ERROR_SERVICE_DEPENDENCY_DELETED));\r
+ return 5;\r
+ }\r
+ }\r
+ else {\r
+ SC_HANDLE dependency_handle = open_service(services, s, SERVICE_QUERY_STATUS, dependency, _countof(dependency));\r
+ if (! dependency_handle) {\r
+ HeapFree(GetProcessHeap(), 0, dependencies);\r
+ if (groups) HeapFree(GetProcessHeap(), 0, groups);\r
+ CloseServiceHandle(services);\r
+ _ftprintf(stderr, _T("%s: %s"), s, error_string(ERROR_SERVICE_DEPENDENCY_DELETED));\r
+ return 5;\r
+ }\r
+ }\r
+\r
+ size_t len = _tcslen(dependency) + 1;\r
+ memmove(dependencies + i, dependency, len * sizeof(TCHAR));\r
+ i += len;\r
+\r
+ while (*s) s++;\r
+ }\r
+\r
+ if (groups) HeapFree(GetProcessHeap(), 0, groups);\r
+ CloseServiceHandle(services);\r
+ }\r
+\r
+ if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, dependencies, 0, 0, 0)) {\r
+ if (num_dependencies) HeapFree(GetProcessHeap(), 0, dependencies);\r
+ print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));\r
+ return -1;\r
+ }\r
+\r
+ if (num_dependencies) HeapFree(GetProcessHeap(), 0, dependencies);\r
+ return 0;\r
+}\r
+\r
+int get_service_dependencies(const TCHAR *service_name, SC_HANDLE service_handle, TCHAR **buffer, unsigned long *bufsize, int type) {\r
+ if (! buffer) return 1;\r
+ if (! bufsize) return 2;\r
+\r
+ *buffer = 0;\r
+ *bufsize = 0;\r
+\r
+ QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);\r
+ if (! qsc) return 3;\r
+\r
+ if (! qsc->lpDependencies) return 0;\r
+ if (! qsc->lpDependencies[0]) return 0;\r
+\r
+ /* 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
+ 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
+ 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
SecureZeroMemory(service->password, service->passwordlen);\r
HeapFree(GetProcessHeap(), 0, service->password);\r
}\r
+ if (service->dependencies) HeapFree(GetProcessHeap(), 0, service->dependencies);\r
if (service->env) HeapFree(GetProcessHeap(), 0, service->env);\r
if (service->env_extra) HeapFree(GetProcessHeap(), 0, service->env_extra);\r
if (service->handle) CloseHandle(service->handle);\r
}\r
}\r
\r
+ if (get_service_dependencies(service->name, service->handle, &service->dependencies, &service->dependencieslen)) {\r
+ if (mode != MODE_GETTING) {\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ return 7;\r
+ }\r
+ }\r
+\r
/* Get NSSM details. */\r
get_parameters(service, 0);\r
\r
}\r
}\r
\r
- if (! ChangeServiceConfig(service->handle, service->type, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, service->displayname)) {\r
+ TCHAR *dependencies = _T("");\r
+ if (service->dependencieslen) dependencies = 0; /* Change later. */\r
+\r
+ if (! ChangeServiceConfig(service->handle, service->type, startup, SERVICE_NO_CHANGE, 0, 0, 0, dependencies, username, password, service->displayname)) {\r
print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));\r
return 5;\r
}\r
\r
+ if (service->dependencieslen) {\r
+ if (set_service_dependencies(service->name, service->handle, service->dependencies)) return 5;\r
+ }\r
+\r
if (service->description[0] || editing) {\r
set_service_description(service->name, service->handle, service->description);\r
}\r
TCHAR dir[DIR_LENGTH];\r
TCHAR *env;\r
__int64 affinity;\r
+ TCHAR *dependencies;\r
+ unsigned long dependencieslen;\r
unsigned long envlen;\r
TCHAR *env_extra;\r
unsigned long env_extralen;\r
SC_HANDLE open_service_manager(unsigned long);\r
SC_HANDLE open_service(SC_HANDLE, TCHAR *, unsigned long, TCHAR *, unsigned long);\r
QUERY_SERVICE_CONFIG *query_service_config(const TCHAR *, SC_HANDLE);\r
+int set_service_dependencies(const TCHAR *, SC_HANDLE, TCHAR *);\r
+int get_service_dependencies(const TCHAR *, SC_HANDLE, TCHAR **, unsigned long *, int);\r
+int get_service_dependencies(const TCHAR *, SC_HANDLE, TCHAR **, unsigned long *);\r
int set_service_description(const TCHAR *, SC_HANDLE, TCHAR *);\r
int get_service_description(const TCHAR *, SC_HANDLE, unsigned long, TCHAR *);\r
int get_service_startup(const TCHAR *, SC_HANDLE, const QUERY_SERVICE_CONFIG *, unsigned long *);\r
}
/* Functions to manage native service settings. */
+static int native_set_dependongroup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
+ SC_HANDLE service_handle = (SC_HANDLE) param;
+ if (! service_handle) return -1;
+
+ /*
+ Get existing service dependencies because we must set both types together.
+ */
+ TCHAR *buffer;
+ unsigned long buflen;
+ if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, DEPENDENCY_SERVICES)) return -1;
+
+ if (! value || ! value->string || ! value->string[0]) {
+ if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, buffer, 0, 0, 0)) {
+ print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return 0;
+ }
+
+ unsigned long len = (unsigned long) _tcslen(value->string) + 1;
+ TCHAR *unformatted = 0;
+ unsigned long newlen;
+ if (unformat_double_null(value->string, len, &unformatted, &newlen)) {
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ /* Prepend group identifier. */
+ unsigned long missing = 0;
+ TCHAR *canon = unformatted;
+ size_t canonlen = 0;
+ TCHAR *s;
+ for (s = unformatted; *s; s++) {
+ if (*s != SC_GROUP_IDENTIFIER) missing++;
+ size_t len = _tcslen(s);
+ canonlen += len + 1;
+ s += len;
+ }
+
+ if (missing) {
+ /* Missing identifiers plus double NULL terminator. */
+ canonlen += missing + 1;
+ newlen = (unsigned long) canonlen;
+
+ canon = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, canonlen * sizeof(TCHAR));
+ if (! canon) {
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("native_set_dependongroup"));
+ if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ size_t i = 0;
+ for (s = unformatted; *s; s++) {
+ if (*s != SC_GROUP_IDENTIFIER) canon[i++] = SC_GROUP_IDENTIFIER;
+ size_t len = _tcslen(s);
+ memmove(canon + i, s, (len + 1) * sizeof(TCHAR));
+ i += len + 1;
+ s += len;
+ }
+ }
+
+ TCHAR *dependencies;
+ if (buflen > 2) {
+ dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (newlen + buflen) * sizeof(TCHAR));
+ if (! dependencies) {
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("dependencies"), _T("native_set_dependongroup"));
+ if (canon != unformatted) HeapFree(GetProcessHeap(), 0, canon);
+ if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ memmove(dependencies, buffer, buflen * sizeof(TCHAR));
+ memmove(dependencies + buflen - 1, canon, newlen * sizeof(TCHAR));
+ }
+ else dependencies = canon;
+
+ int ret = 1;
+ if (set_service_dependencies(service_name, service_handle, dependencies)) ret = -1;
+ if (dependencies != unformatted) HeapFree(GetProcessHeap(), 0, dependencies);
+ if (canon != unformatted) HeapFree(GetProcessHeap(), 0, canon);
+ if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+
+ return ret;
+}
+
+static int native_get_dependongroup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
+ SC_HANDLE service_handle = (SC_HANDLE) param;
+ if (! service_handle) return -1;
+
+ TCHAR *buffer;
+ unsigned long buflen;
+ if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, DEPENDENCY_GROUPS)) return -1;
+
+ int ret;
+ if (buflen) {
+ TCHAR *formatted;
+ unsigned long newlen;
+ if (format_double_null(buffer, buflen, &formatted, &newlen)) {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ ret = value_from_string(name, value, formatted);
+ HeapFree(GetProcessHeap(), 0, formatted);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
+ else {
+ value->string = 0;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int native_set_dependonservice(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
+ SC_HANDLE service_handle = (SC_HANDLE) param;
+ if (! service_handle) return -1;
+
+ /*
+ Get existing group dependencies because we must set both types together.
+ */
+ TCHAR *buffer;
+ unsigned long buflen;
+ if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, DEPENDENCY_GROUPS)) return -1;
+
+ if (! value || ! value->string || ! value->string[0]) {
+ if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, buffer, 0, 0, 0)) {
+ print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return 0;
+ }
+
+ unsigned long len = (unsigned long) _tcslen(value->string) + 1;
+ TCHAR *unformatted = 0;
+ unsigned long newlen;
+ if (unformat_double_null(value->string, len, &unformatted, &newlen)) {
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ TCHAR *dependencies;
+ if (buflen > 2) {
+ dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (newlen + buflen) * sizeof(TCHAR));
+ if (! dependencies) {
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("dependencies"), _T("native_set_dependonservice"));
+ if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ memmove(dependencies, buffer, buflen * sizeof(TCHAR));
+ memmove(dependencies + buflen - 1, unformatted, newlen * sizeof(TCHAR));
+ }
+ else dependencies = unformatted;
+
+ int ret = 1;
+ if (set_service_dependencies(service_name, service_handle, dependencies)) ret = -1;
+ if (dependencies != unformatted) HeapFree(GetProcessHeap(), 0, dependencies);
+ if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);
+ if (buffer) HeapFree(GetProcessHeap(), 0, buffer);
+
+ return ret;
+}
+
+static int native_get_dependonservice(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
+ SC_HANDLE service_handle = (SC_HANDLE) param;
+ if (! service_handle) return -1;
+
+ TCHAR *buffer;
+ unsigned long buflen;
+ if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, DEPENDENCY_SERVICES)) return -1;
+
+ int ret;
+ if (buflen) {
+ TCHAR *formatted;
+ unsigned long newlen;
+ if (format_double_null(buffer, buflen, &formatted, &newlen)) {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return -1;
+ }
+
+ ret = value_from_string(name, value, formatted);
+ HeapFree(GetProcessHeap(), 0, formatted);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
+ else {
+ value->string = 0;
+ ret = 0;
+ }
+
+ return ret;
+}
+
int native_set_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
SC_HANDLE service_handle = (SC_HANDLE) param;
if (! service_handle) return -1;
{ NSSM_REG_ROTATE_SECONDS, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_ROTATE_BYTES_LOW, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_ROTATE_BYTES_HIGH, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
+ { NSSM_NATIVE_DEPENDONGROUP, REG_MULTI_SZ, NULL, true, ADDITIONAL_CRLF, native_set_dependongroup, native_get_dependongroup },
+ { NSSM_NATIVE_DEPENDONSERVICE, REG_MULTI_SZ, NULL, true, ADDITIONAL_CRLF, native_set_dependonservice, native_get_dependonservice },
{ NSSM_NATIVE_DESCRIPTION, REG_SZ, _T(""), true, 0, native_set_description, native_get_description },
{ NSSM_NATIVE_DISPLAYNAME, REG_SZ, NULL, true, 0, native_set_displayname, native_get_displayname },
{ NSSM_NATIVE_IMAGEPATH, REG_EXPAND_SZ, NULL, true, 0, native_set_imagepath, native_get_imagepath },
#ifndef SETTINGS_H
#define SETTINGS_H
+#define NSSM_NATIVE_DEPENDONGROUP _T("DependOnGroup")
+#define NSSM_NATIVE_DEPENDONSERVICE _T("DependOnService")
#define NSSM_NATIVE_DESCRIPTION _T("Description")
#define NSSM_NATIVE_DISPLAYNAME _T("DisplayName")
#define NSSM_NATIVE_IMAGEPATH _T("ImagePath")
#define ADDITIONAL_CRLF (1 << 3)
#define ADDITIONAL_MANDATORY ADDITIONAL_GETTING|ADDITIONAL_SETTING|ADDITIONAL_RESETTING
+#define DEPENDENCY_SERVICES (1 << 0)
+#define DEPENDENCY_GROUPS (1 << 1)
+#define DEPENDENCY_ALL (DEPENDENCY_SERVICES|DEPENDENCY_GROUPS)
+
typedef union {
unsigned long numeric;
TCHAR *string;