2 /* XXX: (value && value->string) is probably bogus because value is probably never null */
4 extern const TCHAR *exit_action_strings[];
5 extern const TCHAR *startup_strings[];
6 extern const TCHAR *priority_strings[];
8 /* Does the parameter refer to the default value of the AppExit setting? */
9 static inline int is_default_exit_action(const TCHAR *value) {
10 return (str_equiv(value, _T("default")) || str_equiv(value, _T("*")) || ! value[0]);
13 static int value_from_string(const TCHAR *name, value_t *value, const TCHAR *string) {
14 size_t len = _tcslen(string);
20 value->string = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));
21 if (! value->string) {
22 print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, name, _T("value_from_string()"));
26 if (_sntprintf_s(value->string, len, _TRUNCATE, _T("%s"), string) < 0) {
27 HeapFree(GetProcessHeap(), 0, value->string);
28 print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, name, _T("value_from_string()"));
35 /* Functions to manage NSSM-specific settings in the registry. */
36 static int setting_set_number(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
37 HKEY key = (HKEY) param;
43 /* Resetting to default? */
44 if (! value || ! value->string) {
45 error = RegDeleteValue(key, name);
46 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
47 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
50 if (str_number(value->string, &number)) return -1;
52 if (default_value && number == (unsigned long) default_value) {
53 error = RegDeleteValue(key, name);
54 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
55 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
59 if (set_number(key, (TCHAR *) name, number)) return -1;
64 static int setting_get_number(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
65 HKEY key = (HKEY) param;
66 return get_number(key, (TCHAR *) name, &value->numeric, false);
69 static int setting_set_string(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
70 HKEY key = (HKEY) param;
75 /* Resetting to default? */
76 if (! value || ! value->string) {
77 if (default_value) value->string = (TCHAR *) default_value;
79 error = RegDeleteValue(key, name);
80 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
81 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
85 if (default_value && _tcslen((TCHAR *) default_value) && str_equiv(value->string, (TCHAR *) default_value)) {
86 error = RegDeleteValue(key, name);
87 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
88 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
92 if (set_expand_string(key, (TCHAR *) name, value->string)) return -1;
97 static int setting_get_string(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
98 HKEY key = (HKEY) param;
99 TCHAR buffer[VALUE_LENGTH];
101 if (expand_parameter(key, (TCHAR *) name, (TCHAR *) buffer, (unsigned long) sizeof(buffer), false, false)) return -1;
103 return value_from_string(name, value, buffer);
106 static int setting_set_exit_action(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
107 unsigned long exitcode;
109 TCHAR action_string[ACTION_LEN];
112 /* Default action? */
113 if (is_default_exit_action(additional)) code = 0;
115 if (str_number(additional, &exitcode)) return -1;
116 code = (TCHAR *) additional;
120 HKEY key = open_registry(service_name, name, KEY_WRITE);
121 if (! key) return -1;
126 /* Resetting to default? */
127 if (value && value->string) _sntprintf_s(action_string, _countof(action_string), _TRUNCATE, _T("%s"), value->string);
130 /* Delete explicit action. */
131 error = RegDeleteValue(key, code);
133 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
134 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, code, service_name, error_string(error));
138 /* Explicitly keep the default action. */
139 if (default_value) _sntprintf_s(action_string, _countof(action_string), _TRUNCATE, _T("%s"), (TCHAR *) default_value);
144 /* Validate the string. */
145 for (int i = 0; exit_action_strings[i]; i++) {
146 if (! _tcsnicmp((const TCHAR *) action_string, exit_action_strings[i], ACTION_LEN)) {
147 if (default_value && str_equiv(action_string, (TCHAR *) default_value)) ret = 0;
148 if (RegSetValueEx(key, code, 0, REG_SZ, (const unsigned char *) action_string, (unsigned long) (_tcslen(action_string) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) {
149 print_message(stderr, NSSM_MESSAGE_SETVALUE_FAILED, code, service_name, error_string(GetLastError()));
159 print_message(stderr, NSSM_MESSAGE_INVALID_EXIT_ACTION, action_string);
160 for (int i = 0; exit_action_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), exit_action_strings[i]);
165 static int setting_get_exit_action(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
166 unsigned long exitcode = 0;
167 unsigned long *code = 0;
170 if (! is_default_exit_action(additional)) {
171 if (str_number(additional, &exitcode)) return -1;
176 TCHAR action_string[ACTION_LEN];
178 if (get_exit_action(service_name, code, action_string, &default_action)) return -1;
180 value_from_string(name, value, action_string);
182 if (default_action && ! _tcsnicmp((const TCHAR *) action_string, (TCHAR *) default_value, ACTION_LEN)) return 0;
186 static int setting_set_environment(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
187 HKEY key = (HKEY) param;
188 if (! param) return -1;
190 if (! value || ! value->string || ! value->string[0]) {
191 long error = RegDeleteValue(key, name);
192 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
193 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
197 unsigned long envlen = (unsigned long) _tcslen(value->string) + 1;
198 TCHAR *unformatted = 0;
199 unsigned long newlen;
200 if (unformat_environment(value->string, envlen, &unformatted, &newlen)) return -1;
202 if (test_environment(unformatted)) {
203 HeapFree(GetProcessHeap(), 0, unformatted);
204 print_message(stderr, NSSM_GUI_INVALID_ENVIRONMENT);
208 if (RegSetValueEx(key, name, 0, REG_MULTI_SZ, (const unsigned char *) unformatted, (unsigned long) newlen * sizeof(TCHAR)) != ERROR_SUCCESS) {
209 if (newlen) HeapFree(GetProcessHeap(), 0, unformatted);
210 log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);
214 if (newlen) HeapFree(GetProcessHeap(), 0, unformatted);
218 static int setting_get_environment(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
219 HKEY key = (HKEY) param;
220 if (! param) return -1;
223 unsigned long envlen;
224 if (set_environment((TCHAR *) service_name, key, (TCHAR *) name, &env, &envlen)) return -1;
225 if (! envlen) return 0;
228 unsigned long newlen;
229 if (format_environment(env, envlen, &formatted, &newlen)) return -1;
233 /* Find named environment variable. */
235 size_t len = _tcslen(additional);
236 for (s = env; *s; s++) {
237 /* Look for <additional>=<string> NULL NULL */
238 if (! _tcsnicmp(s, additional, len) && s[len] == _T('=')) {
241 ret = value_from_string(name, value, s);
242 HeapFree(GetProcessHeap(), 0, env);
246 /* Skip this string. */
249 HeapFree(GetProcessHeap(), 0, env);
253 HeapFree(GetProcessHeap(), 0, env);
255 ret = value_from_string(name, value, formatted);
256 if (newlen) HeapFree(GetProcessHeap(), 0, formatted);
260 static int setting_set_priority(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
261 HKEY key = (HKEY) param;
262 if (! param) return -1;
264 TCHAR *priority_string;
268 if (value && value->string) priority_string = value->string;
269 else if (default_value) priority_string = (TCHAR *) default_value;
271 error = RegDeleteValue(key, name);
272 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
273 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
277 for (i = 0; priority_strings[i]; i++) {
278 if (! str_equiv(priority_strings[i], priority_string)) continue;
280 if (default_value && str_equiv(priority_string, (TCHAR *) default_value)) {
281 error = RegDeleteValue(key, name);
282 if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
283 print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
287 if (set_number(key, (TCHAR *) name, priority_index_to_constant(i))) return -1;
291 print_message(stderr, NSSM_MESSAGE_INVALID_PRIORITY, priority_string);
292 for (i = 0; priority_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), priority_strings[i]);
297 static int setting_get_priority(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
298 HKEY key = (HKEY) param;
299 if (! param) return -1;
301 unsigned long constant;
302 switch (get_number(key, (TCHAR *) name, &constant, false)) {
303 case 0: return value_from_string(name, value, (const TCHAR *) default_value);
307 return value_from_string(name, value, priority_strings[priority_constant_to_index(constant)]);
310 /* Functions to manage native service settings. */
311 int native_set_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
312 SC_HANDLE service_handle = (SC_HANDLE) param;
313 if (! service_handle) return -1;
315 TCHAR *description = 0;
316 if (value) description = value->string;
317 if (set_service_description(service_name, service_handle, description)) return -1;
319 if (description && description[0]) return 1;
324 int native_get_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
325 SC_HANDLE service_handle = (SC_HANDLE) param;
326 if (! service_handle) return -1;
328 TCHAR buffer[VALUE_LENGTH];
329 if (get_service_description(service_name, service_handle, _countof(buffer), buffer)) return -1;
331 if (buffer[0]) return value_from_string(name, value, buffer);
337 int native_set_displayname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
338 SC_HANDLE service_handle = (SC_HANDLE) param;
339 if (! service_handle) return -1;
341 TCHAR *displayname = 0;
342 if (value && value->string) displayname = value->string;
343 else displayname = (TCHAR *) service_name;
345 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, displayname)) {
346 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
351 If the display name and service name differ only in case,
352 ChangeServiceConfig() will return success but the display name will be
353 set to the service name, NOT the value passed to the function.
354 This appears to be a quirk of Windows rather than a bug here.
356 if (displayname != service_name && ! str_equiv(displayname, service_name)) return 1;
361 int native_get_displayname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
362 SC_HANDLE service_handle = (SC_HANDLE) param;
363 if (! service_handle) return -1;
365 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
366 if (! qsc) return -1;
368 int ret = value_from_string(name, value, qsc->lpDisplayName);
369 HeapFree(GetProcessHeap(), 0, qsc);
374 int native_set_imagepath(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
375 SC_HANDLE service_handle = (SC_HANDLE) param;
376 if (! service_handle) return -1;
378 /* It makes no sense to try to reset the image path. */
379 if (! value || ! value->string) {
380 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
384 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, value->string, 0, 0, 0, 0, 0, 0)) {
385 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
392 int native_get_imagepath(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
393 SC_HANDLE service_handle = (SC_HANDLE) param;
394 if (! service_handle) return -1;
396 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
397 if (! qsc) return -1;
399 int ret = value_from_string(name, value, qsc->lpBinaryPathName);
400 HeapFree(GetProcessHeap(), 0, qsc);
405 int native_set_name(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
406 print_message(stderr, NSSM_MESSAGE_CANNOT_RENAME_SERVICE);
410 int native_get_name(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
411 return value_from_string(name, value, service_name);
414 int native_set_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
415 SC_HANDLE service_handle = (SC_HANDLE) param;
416 if (! service_handle) return -1;
419 Logical syntax is: nssm set <service> ObjectName <username> <password>
420 That means the username is actually passed in the additional parameter.
422 bool localsystem = true;
423 TCHAR *username = NSSM_LOCALSYSTEM_ACCOUNT;
426 if (! str_equiv(additional, NSSM_LOCALSYSTEM_ACCOUNT)) {
428 username = (TCHAR *) additional;
429 if (value && value->string) password = value->string;
431 /* We need a password if the account is not LOCALSYSTEM. */
432 print_message(stderr, NSSM_MESSAGE_MISSING_PASSWORD, name);
439 ChangeServiceConfig() will fail to set the username if the service is set
440 to interact with the desktop.
442 unsigned long type = SERVICE_NO_CHANGE;
444 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
446 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
450 type = qsc->dwServiceType & ~SERVICE_INTERACTIVE_PROCESS;
451 HeapFree(GetProcessHeap(), 0, qsc);
454 if (grant_logon_as_service(username)) {
455 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
456 print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);
460 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, 0)) {
461 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
462 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
465 if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
467 if (localsystem) return 0;
472 int native_get_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
473 SC_HANDLE service_handle = (SC_HANDLE) param;
474 if (! service_handle) return -1;
476 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
477 if (! qsc) return -1;
479 int ret = value_from_string(name, value, qsc->lpServiceStartName);
480 HeapFree(GetProcessHeap(), 0, qsc);
485 int native_set_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
486 SC_HANDLE service_handle = (SC_HANDLE) param;
487 if (! service_handle) return -1;
489 /* It makes no sense to try to reset the startup type. */
490 if (! value || ! value->string) {
491 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
495 /* Map NSSM_STARTUP_* constant to Windows SERVICE_*_START constant. */
496 int service_startup = -1;
498 for (i = 0; startup_strings[i]; i++) {
499 if (str_equiv(value->string, startup_strings[i])) {
505 if (service_startup < 0) {
506 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_STARTUP, value->string);
507 for (i = 0; startup_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), startup_strings[i]);
511 unsigned long startup;
512 switch (service_startup) {
513 case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break;
514 case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break;
515 default: startup = SERVICE_AUTO_START;
518 if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
519 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
523 SERVICE_DELAYED_AUTO_START_INFO delayed;
524 ZeroMemory(&delayed, sizeof(delayed));
525 if (service_startup == NSSM_STARTUP_DELAYED) delayed.fDelayedAutostart = 1;
526 else delayed.fDelayedAutostart = 0;
527 if (! ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {
528 unsigned long error = GetLastError();
529 /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */
530 if (error != ERROR_INVALID_LEVEL) {
531 log_event(EVENTLOG_ERROR_TYPE, NSSM_MESSAGE_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service_name, error_string(error), 0);
538 int native_get_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
539 SC_HANDLE service_handle = (SC_HANDLE) param;
540 if (! service_handle) return -1;
542 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
543 if (! qsc) return -1;
545 unsigned long startup;
546 int ret = get_service_startup(service_name, service_handle, qsc, &startup);
547 HeapFree(GetProcessHeap(), 0, qsc);
552 for (i = 0; startup_strings[i]; i++);
553 if (startup >= i) return -1;
555 return value_from_string(name, value, startup_strings[startup]);
558 int native_set_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
559 SC_HANDLE service_handle = (SC_HANDLE) param;
560 if (! service_handle) return -1;
562 /* It makes no sense to try to reset the service type. */
563 if (! value || ! value->string) {
564 print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
569 We can only manage services of type SERVICE_WIN32_OWN_PROCESS
570 and SERVICE_INTERACTIVE_PROCESS.
572 unsigned long type = SERVICE_WIN32_OWN_PROCESS;
573 if (str_equiv(value->string, NSSM_INTERACTIVE_PROCESS)) type |= SERVICE_INTERACTIVE_PROCESS;
574 else if (! str_equiv(value->string, NSSM_WIN32_OWN_PROCESS)) {
575 print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_TYPE, value->string);
576 _ftprintf(stderr, _T("%s\n"), NSSM_WIN32_OWN_PROCESS);
577 _ftprintf(stderr, _T("%s\n"), NSSM_INTERACTIVE_PROCESS);
582 ChangeServiceConfig() will fail if the service runs under an account
583 other than LOCALSYSTEM and we try to make it interactive.
585 if (type & SERVICE_INTERACTIVE_PROCESS) {
586 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
587 if (! qsc) return -1;
589 if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) {
590 HeapFree(GetProcessHeap(), 0, qsc);
591 print_message(stderr, NSSM_MESSAGE_INTERACTIVE_NOT_LOCALSYSTEM, value->string, service_name, NSSM_LOCALSYSTEM_ACCOUNT);
595 HeapFree(GetProcessHeap(), 0, qsc);
598 if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
599 print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
606 int native_get_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
607 SC_HANDLE service_handle = (SC_HANDLE) param;
608 if (! service_handle) return -1;
610 QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
611 if (! qsc) return -1;
613 value->numeric = qsc->dwServiceType;
614 HeapFree(GetProcessHeap(), 0, qsc);
617 switch (value->numeric) {
618 case SERVICE_KERNEL_DRIVER: string = NSSM_KERNEL_DRIVER; break;
619 case SERVICE_FILE_SYSTEM_DRIVER: string = NSSM_FILE_SYSTEM_DRIVER; break;
620 case SERVICE_WIN32_OWN_PROCESS: string = NSSM_WIN32_OWN_PROCESS; break;
621 case SERVICE_WIN32_SHARE_PROCESS: string = NSSM_WIN32_SHARE_PROCESS; break;
622 case SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_INTERACTIVE_PROCESS; break;
623 case SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_SHARE_INTERACTIVE_PROCESS; break;
624 default: string = NSSM_UNKNOWN;
627 return value_from_string(name, value, string);
630 int set_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
631 if (! key) return -1;
634 if (setting->set) ret = setting->set(service_name, (void *) key, setting->name, setting->default_value, value, additional);
637 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
638 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
639 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
644 int set_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
645 if (! service_handle) return -1;
648 if (setting->set) ret = setting->set(service_name, service_handle, setting->name, setting->default_value, value, additional);
651 if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
652 else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
653 else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
659 Returns: 1 if the value was retrieved.
660 0 if the default value was retrieved.
663 int get_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
664 if (! key) return -1;
667 switch (setting->type) {
671 value->string = (TCHAR *) setting->default_value;
672 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
677 value->numeric = (unsigned long) setting->default_value;
678 if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
687 if (ret < 0) print_message(stderr, NSSM_MESSAGE_GET_SETTING_FAILED, setting->name, service_name);
692 int get_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
693 if (! service_handle) return -1;
694 return setting->get(service_name, service_handle, setting->name, 0, value, additional);
697 settings_t settings[] = {
698 { NSSM_REG_EXE, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
699 { NSSM_REG_FLAGS, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
700 { NSSM_REG_DIR, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
701 { NSSM_REG_EXIT, REG_SZ, (void *) exit_action_strings[NSSM_EXIT_RESTART], false, ADDITIONAL_MANDATORY, setting_set_exit_action, setting_get_exit_action },
702 { NSSM_REG_ENV, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
703 { NSSM_REG_ENV_EXTRA, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
704 { NSSM_REG_PRIORITY, REG_SZ, (void *) priority_strings[NSSM_NORMAL_PRIORITY], false, 0, setting_set_priority, setting_get_priority },
705 { NSSM_REG_STDIN, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
706 { NSSM_REG_STDIN NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDIN_SHARING, false, 0, setting_set_number, setting_get_number },
707 { NSSM_REG_STDIN NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDIN_DISPOSITION, false, 0, setting_set_number, setting_get_number },
708 { NSSM_REG_STDIN NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDIN_FLAGS, false, 0, setting_set_number, setting_get_number },
709 { NSSM_REG_STDOUT, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
710 { NSSM_REG_STDOUT NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDOUT_SHARING, false, 0, setting_set_number, setting_get_number },
711 { NSSM_REG_STDOUT NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDOUT_DISPOSITION, false, 0, setting_set_number, setting_get_number },
712 { NSSM_REG_STDOUT NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDOUT_FLAGS, false, 0, setting_set_number, setting_get_number },
713 { NSSM_REG_STDERR, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
714 { NSSM_REG_STDERR NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDERR_SHARING, false, 0, setting_set_number, setting_get_number },
715 { NSSM_REG_STDERR NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDERR_DISPOSITION, false, 0, setting_set_number, setting_get_number },
716 { NSSM_REG_STDERR NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDERR_FLAGS, false, 0, setting_set_number, setting_get_number },
717 { NSSM_REG_STOP_METHOD_SKIP, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
718 { NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
719 { NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
720 { NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
721 { NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
722 { NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
723 { NSSM_REG_ROTATE_SECONDS, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
724 { NSSM_REG_ROTATE_BYTES_LOW, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
725 { NSSM_REG_ROTATE_BYTES_HIGH, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
726 { NSSM_NATIVE_DESCRIPTION, REG_SZ, _T(""), true, 0, native_set_description, native_get_description },
727 { NSSM_NATIVE_DISPLAYNAME, REG_SZ, NULL, true, 0, native_set_displayname, native_get_displayname },
728 { NSSM_NATIVE_IMAGEPATH, REG_EXPAND_SZ, NULL, true, 0, native_set_imagepath, native_get_imagepath },
729 { NSSM_NATIVE_OBJECTNAME, REG_SZ, NSSM_LOCALSYSTEM_ACCOUNT, true, ADDITIONAL_SETTING, native_set_objectname, native_get_objectname },
730 { NSSM_NATIVE_NAME, REG_SZ, NULL, true, 0, native_set_name, native_get_name },
731 { NSSM_NATIVE_STARTUP, REG_SZ, NULL, true, 0, native_set_startup, native_get_startup },
732 { NSSM_NATIVE_TYPE, REG_SZ, NULL, true, 0, native_set_type, native_get_type },
733 { NULL, NULL, NULL, NULL, NULL }