"nssm edit <service>" brings up a GUI to edit an existing service.
Services not managed by NSSM can also be edited but only system
properties such as the display name will appear in the GUI.
Changes since 2.21
------------------
+ * Existing services can now be edited using the GUI.
+
* NSSM can now optionally rotate existing files when
redirecting I/O.
Since version 2.22, NSSM can set service display name, description, startup\r
type and log on details.\r
\r
+Since version 2.22, NSSM can edit existing services with the GUI.\r
+\r
\r
Usage\r
-----\r
srvany only supports AppEnvironment.\r
\r
\r
+Managing services using the GUI\r
+-------------------------------\r
+NSSM can edit the settings of existing services with the same GUI that is\r
+used to install them. Run\r
+\r
+ nssm edit <servicename>\r
+\r
+to bring up the GUI.\r
+\r
+NSSM offers limited editing capabilities for services other than those which\r
+run NSSM itself. When NSSM is asked to edit a service which does not have\r
+the App* registry settings described above, the GUI will allow editing only\r
+system settings such as the service display name and description.\r
+\r
+\r
Removing services using the GUI\r
-------------------------------\r
NSSM can also remove services. Run\r
return 1;\r
}\r
\r
+ /* Remember what the window is for. */\r
+ SetWindowLongPtr(dlg, GWLP_USERDATA, (LONG_PTR) resource);\r
+\r
/* Display the window */\r
centre_window(dlg);\r
ShowWindow(dlg, SW_SHOW);\r
}\r
}\r
\r
+ if (resource == IDD_EDIT) {\r
+ /* We'll need the service handle later. */\r
+ SetWindowLongPtr(dlg, DWLP_USER, (LONG_PTR) service);\r
+\r
+ /* Service name can't be edited. */\r
+ EnableWindow(GetDlgItem(dlg, IDC_NAME), 0);\r
+ SetFocus(GetDlgItem(dlg, IDOK));\r
+\r
+ /* Set existing details. */\r
+ HWND combo;\r
+\r
+ /* Application tab. */\r
+ if (service->native) SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->image);\r
+ else SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->exe);\r
+ SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_DIR, service->dir);\r
+ SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS, service->flags);\r
+\r
+ /* Details tab. */\r
+ SetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname);\r
+ SetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description);\r
+ combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
+ SendMessage(combo, CB_SETCURSEL, service->startup, 0);\r
+\r
+ /* Log on tab. */\r
+ if (service->username) {\r
+ CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_ACCOUNT);\r
+ SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), 0);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), 1);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), 1);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), 1);\r
+ }\r
+ else {\r
+ CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
+ if (service->type & SERVICE_INTERACTIVE_PROCESS) SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_SETCHECK, BST_CHECKED, 0);\r
+ }\r
+\r
+ /* Shutdown tab. */\r
+ if (! (service->stop_method & NSSM_STOP_METHOD_CONSOLE)) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_CONSOLE, BM_SETCHECK, BST_UNCHECKED, 0);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE), 0);\r
+ }\r
+ SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, service->kill_console_delay, 0);\r
+ if (! (service->stop_method & NSSM_STOP_METHOD_WINDOW)) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_WINDOW, BM_SETCHECK, BST_UNCHECKED, 0);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW), 0);\r
+ }\r
+ SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, service->kill_window_delay, 0);\r
+ if (! (service->stop_method & NSSM_STOP_METHOD_THREADS)) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_UNCHECKED, 0);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS), 0);\r
+ }\r
+ SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, service->kill_threads_delay, 0);\r
+ if (! (service->stop_method & NSSM_STOP_METHOD_TERMINATE)) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_UNCHECKED, 0);\r
+ }\r
+\r
+ /* Restart tab. */\r
+ SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, service->throttle_delay, 0);\r
+ combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
+ SendMessage(combo, CB_SETCURSEL, service->default_exit_action, 0);\r
+\r
+ /* I/O tab. */\r
+ SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDIN, service->stdin_path);\r
+ SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDOUT, service->stdout_path);\r
+ SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDERR, service->stderr_path);\r
+\r
+ /* Rotation tab. */\r
+ if (service->stdout_disposition == CREATE_ALWAYS) SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_SETCHECK, BST_CHECKED, 0);\r
+ if (service->rotate_files) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_SETCHECK, BST_CHECKED, 0);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS), 1);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), 1);\r
+ }\r
+ SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, service->rotate_seconds, 0);\r
+ if (! service->rotate_bytes_high) SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, service->rotate_bytes_low, 0);\r
+\r
+ /* Check if advanced settings are in use. */\r
+ if (service->stdout_disposition ^ service->stderr_disposition || service->stdout_disposition & ~CREATE_ALWAYS || service->stderr_disposition & ~CREATE_ALWAYS) popup_message(MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_STDIO);\r
+ if (service->rotate_bytes_high) popup_message(MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ROTATE_BYTES);\r
+\r
+ /* Environment tab. */\r
+ TCHAR *env;\r
+ unsigned long envlen;\r
+ if (service->env_extralen) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_SETCHECK, BST_CHECKED, 0);\r
+ env = service->env_extra;\r
+ envlen = service->env_extralen;\r
+ }\r
+ else {\r
+ env = service->env;\r
+ envlen = service->envlen;\r
+ }\r
+\r
+ if (envlen) {\r
+ /* Replace NULL with CRLF. Leave NULL NULL as the end marker. */\r
+ unsigned long i, j;\r
+ unsigned long newlen = envlen;\r
+ for (i = 0; i < envlen; i++) if (! env[i] && env[i + 1]) newlen++;\r
+\r
+ TCHAR *formatted = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen * sizeof(TCHAR));\r
+ if (formatted) {\r
+ for (i = 0, j = 0; i < envlen; i++) {\r
+ formatted[j] = env[i];\r
+ if (! env[i]) {\r
+ if (env[i + 1]) {\r
+ formatted[j] = _T('\r');\r
+ formatted[++j] = _T('\n');\r
+ }\r
+ }\r
+ j++;\r
+ }\r
+ SetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, formatted);\r
+ HeapFree(GetProcessHeap(), 0, formatted);\r
+ }\r
+ else popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("nssm_dlg()"));\r
+ }\r
+ if (service->envlen && service->env_extralen) popup_message(MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ENVIRONMENT);\r
+ }\r
+\r
/* Go! */\r
MSG message;\r
while (GetMessage(&message, 0, 0, 0)) {\r
ZeroMemory(buffer, len * sizeof(TCHAR));\r
}\r
\r
-/* Install the service. */\r
-int install(HWND window) {\r
- if (! window) return 1;\r
+/* Set service parameters. */\r
+int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service) {\r
+ if (! service) return 1;\r
\r
- nssm_service_t *service = alloc_nssm_service();\r
- if (service) {\r
- set_nssm_service_defaults(service);\r
+ set_nssm_service_defaults(service);\r
\r
- /* Get service name. */\r
- if (! GetDlgItemText(window, IDC_NAME, service->name, _countof(service->name))) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
- cleanup_nssm_service(service);\r
- return 2;\r
- }\r
+ if (orig_service) {\r
+ service->native = orig_service->native;\r
+ service->handle = orig_service->handle;\r
+ }\r
\r
- /* Get executable name */\r
+ /* Get service name. */\r
+ if (! GetDlgItemText(window, IDC_NAME, service->name, _countof(service->name))) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
+ cleanup_nssm_service(service);\r
+ return 2;\r
+ }\r
+\r
+ /* Get executable name */\r
+ if (! service->native) {\r
if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->exe, _countof(service->exe))) {\r
popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PATH);\r
return 3;\r
return 4;\r
}\r
}\r
+ }\r
\r
- /* Get details. */\r
- if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME), WM_GETTEXTLENGTH, 0, 0)) {\r
- if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname, _countof(service->displayname))) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DISPLAYNAME);\r
- return 5;\r
- }\r
+ /* Get details. */\r
+ if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME), WM_GETTEXTLENGTH, 0, 0)) {\r
+ if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname, _countof(service->displayname))) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DISPLAYNAME);\r
+ return 5;\r
}\r
+ }\r
\r
- if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION), WM_GETTEXTLENGTH, 0, 0)) {\r
- if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description, _countof(service->description))) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DESCRIPTION);\r
- return 5;\r
- }\r
+ if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION), WM_GETTEXTLENGTH, 0, 0)) {\r
+ if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description, _countof(service->description))) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DESCRIPTION);\r
+ return 5;\r
}\r
+ }\r
\r
- HWND combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
- service->startup = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
- if (service->startup == CB_ERR) service->startup = 0;\r
+ HWND combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
+ service->startup = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
+ if (service->startup == CB_ERR) service->startup = 0;\r
\r
- /* Get logon stuff. */\r
- if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
- if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
- service->type |= SERVICE_INTERACTIVE_PROCESS;\r
- }\r
+ /* Get logon stuff. */\r
+ if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+ if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+ service->type |= SERVICE_INTERACTIVE_PROCESS;\r
}\r
- else {\r
- /* Username. */\r
- service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
- if (! service->usernamelen) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_USERNAME);\r
- return 6;\r
- }\r
- service->usernamelen++;\r
+ if (service->username) HeapFree(GetProcessHeap(), 0, service->username);\r
+ service->username = 0;\r
+ service->usernamelen = 0;\r
+ if (service->password) {\r
+ SecureZeroMemory(service->password, service->passwordlen);\r
+ HeapFree(GetProcessHeap(), 0, service->password);\r
+ }\r
+ service->password = 0;\r
+ service->passwordlen = 0;\r
+ }\r
+ else {\r
+ /* Username. */\r
+ service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
+ if (! service->usernamelen) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_USERNAME);\r
+ return 6;\r
+ }\r
+ service->usernamelen++;\r
\r
- service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
- if (! service->username) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
- return 6;\r
- }\r
- if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username, (int) service->usernamelen)) {\r
- HeapFree(GetProcessHeap(), 0, service->username);\r
- service->username = 0;\r
- service->usernamelen = 0;\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_USERNAME);\r
- return 6;\r
- }\r
+ service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
+ if (! service->username) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
+ return 6;\r
+ }\r
+ if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username, (int) service->usernamelen)) {\r
+ HeapFree(GetProcessHeap(), 0, service->username);\r
+ service->username = 0;\r
+ service->usernamelen = 0;\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_USERNAME);\r
+ return 6;\r
+ }\r
\r
+ /*\r
+ Special case LOCALSYSTEM.\r
+ Ignore the password if we're editing and the username hasn't changed.\r
+ */\r
+ if (str_equiv(service->username, NSSM_LOCALSYSTEM_ACCOUNT)) {\r
+ HeapFree(GetProcessHeap(), 0, service->username);\r
+ service->username = 0;\r
+ service->usernamelen = 0;\r
+ }\r
+ else if (! orig_service || ! orig_service->username || ! str_equiv(service->username, orig_service->username)) {\r
/* Password. */\r
service->passwordlen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), WM_GETTEXTLENGTH, 0, 0);\r
if (! service->passwordlen) {\r
return 6;\r
}\r
}\r
+ }\r
\r
- /* Get stop method stuff. */\r
- check_stop_method(service, NSSM_STOP_METHOD_CONSOLE, IDC_METHOD_CONSOLE);\r
- check_stop_method(service, NSSM_STOP_METHOD_WINDOW, IDC_METHOD_WINDOW);\r
- check_stop_method(service, NSSM_STOP_METHOD_THREADS, IDC_METHOD_THREADS);\r
- check_stop_method(service, NSSM_STOP_METHOD_TERMINATE, IDC_METHOD_TERMINATE);\r
- check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, &service->kill_console_delay);\r
- check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);\r
- check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);\r
-\r
- /* Get exit action stuff. */\r
- check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
- combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
- service->default_exit_action = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
- if (service->default_exit_action == CB_ERR) service->default_exit_action = 0;\r
+ /* Remaining tabs are only for services we manage. */\r
+ if (service->native) return 0;\r
+\r
+ /* Get stop method stuff. */\r
+ check_stop_method(service, NSSM_STOP_METHOD_CONSOLE, IDC_METHOD_CONSOLE);\r
+ check_stop_method(service, NSSM_STOP_METHOD_WINDOW, IDC_METHOD_WINDOW);\r
+ check_stop_method(service, NSSM_STOP_METHOD_THREADS, IDC_METHOD_THREADS);\r
+ check_stop_method(service, NSSM_STOP_METHOD_TERMINATE, IDC_METHOD_TERMINATE);\r
+ check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, &service->kill_console_delay);\r
+ check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);\r
+ check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);\r
+\r
+ /* Get exit action stuff. */\r
+ check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
+ combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
+ service->default_exit_action = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
+ if (service->default_exit_action == CB_ERR) service->default_exit_action = 0;\r
+\r
+ /* Get I/O stuff. */\r
+ check_io(_T("stdin"), service->stdin_path, _countof(service->stdin_path), IDC_STDIN);\r
+ check_io(_T("stdout"), service->stdout_path, _countof(service->stdout_path), IDC_STDOUT);\r
+ check_io(_T("stderr"), service->stderr_path, _countof(service->stderr_path), IDC_STDERR);\r
+\r
+ /* Override stdout and/or stderr. */\r
+ if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+ if (service->stdout_path[0]) service->stdout_disposition = CREATE_ALWAYS;\r
+ if (service->stderr_path[0]) service->stderr_disposition = CREATE_ALWAYS;\r
+ }\r
\r
- /* Get I/O stuff. */\r
- check_io(_T("stdin"), service->stdin_path, _countof(service->stdin_path), IDC_STDIN);\r
- check_io(_T("stdout"), service->stdout_path, _countof(service->stdout_path), IDC_STDOUT);\r
- check_io(_T("stderr"), service->stderr_path, _countof(service->stderr_path), IDC_STDERR);\r
+ /* Get rotation stuff. */\r
+ if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+ service->rotate_files = true;\r
+ check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
+ check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
+ }\r
\r
- /* Override stdout and/or stderr. */\r
- if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
- if (service->stdout_path[0]) service->stdout_disposition = CREATE_ALWAYS;\r
- if (service->stderr_path[0]) service->stderr_disposition = CREATE_ALWAYS;\r
+ /* Get environment. */\r
+ unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);\r
+ if (envlen) {\r
+ TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (envlen + 2) * sizeof(TCHAR));\r
+ if (! env) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
+ cleanup_nssm_service(service);\r
+ return 5;\r
}\r
\r
- /* Get rotation stuff. */\r
- if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
- service->rotate_files = true;\r
- check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
- check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
+ if (! GetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, env, envlen + 1)) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
+ HeapFree(GetProcessHeap(), 0, env);\r
+ cleanup_nssm_service(service);\r
+ return 5;\r
}\r
\r
- /* Get environment. */\r
- unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);\r
- if (envlen) {\r
- TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (envlen + 2) * sizeof(TCHAR));\r
- if (! env) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
- cleanup_nssm_service(service);\r
- return 5;\r
- }\r
+ /* Strip CR and replace LF with NULL. */\r
+ unsigned long newlen = 0;\r
+ unsigned long i, j;\r
+ for (i = 0; i < envlen; i++) if (env[i] != _T('\r')) newlen++;\r
+ /* Must end with two NULLs. */\r
+ newlen += 2;\r
\r
- if (! GetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, env, envlen + 1)) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
- HeapFree(GetProcessHeap(), 0, env);\r
- cleanup_nssm_service(service);\r
- return 5;\r
- }\r
+ TCHAR *newenv = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen * sizeof(TCHAR));\r
+ if (! newenv) {\r
+ HeapFree(GetProcessHeap(), 0, env);\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
+ cleanup_nssm_service(service);\r
+ return 5;\r
+ }\r
\r
- /* Strip CR and replace LF with NULL. */\r
- unsigned long newlen = 0;\r
- unsigned long i, j;\r
- for (i = 0; i < envlen; i++) if (env[i] != _T('\r')) newlen++;\r
- /* Must end with two NULLs. */\r
- newlen += 2;\r
-\r
- TCHAR *newenv = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen * sizeof(TCHAR));\r
- if (! newenv) {\r
- HeapFree(GetProcessHeap(), 0, env);\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
- cleanup_nssm_service(service);\r
- return 5;\r
- }\r
+ for (i = 0, j = 0; i < envlen; i++) {\r
+ if (env[i] == _T('\r')) continue;\r
+ if (env[i] == _T('\n')) newenv[j] = _T('\0');\r
+ else newenv[j] = env[i];\r
+ j++;\r
+ }\r
\r
- for (i = 0, j = 0; i < envlen; i++) {\r
- if (env[i] == _T('\r')) continue;\r
- if (env[i] == _T('\n')) newenv[j] = _T('\0');\r
- else newenv[j] = env[i];\r
- j++;\r
- }\r
+ HeapFree(GetProcessHeap(), 0, env);\r
+ env = newenv;\r
+ envlen = newlen;\r
\r
+ /* Test the environment is valid. */\r
+ if (test_environment(env)) {\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
HeapFree(GetProcessHeap(), 0, env);\r
- env = newenv;\r
- envlen = newlen;\r
-\r
- /* Test the environment is valid. */\r
- if (test_environment(env)) {\r
- popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
- HeapFree(GetProcessHeap(), 0, env);\r
- cleanup_nssm_service(service);\r
- return 5;\r
- }\r
+ cleanup_nssm_service(service);\r
+ return 5;\r
+ }\r
\r
- if (SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
- service->env = env;\r
- service->envlen = envlen;\r
- }\r
- else {\r
- service->env_extra = env;\r
- service->env_extralen = envlen;\r
- }\r
+ if (SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+ service->env = env;\r
+ service->envlen = envlen;\r
}\r
+ else {\r
+ service->env_extra = env;\r
+ service->env_extralen = envlen;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/* Install the service. */\r
+int install(HWND window) {\r
+ if (! window) return 1;\r
+\r
+ nssm_service_t *service = alloc_nssm_service();\r
+ if (service) {\r
+ int ret = configure(window, service, 0);\r
+ if (ret) return ret;\r
}\r
\r
/* See if it works. */\r
return 0;\r
}\r
\r
+int edit(HWND window, nssm_service_t *orig_service) {\r
+ if (! window) return 1;\r
+\r
+ nssm_service_t *service = alloc_nssm_service();\r
+ if (service) {\r
+ int ret = configure(window, service, orig_service);\r
+ if (ret) return ret;\r
+ }\r
+\r
+ switch (edit_service(service, true)) {\r
+ case 1:\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("edit()"));\r
+ cleanup_nssm_service(service);\r
+ return 1;\r
+\r
+ case 3:\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);\r
+ cleanup_nssm_service(service);\r
+ return 3;\r
+\r
+ case 4:\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH);\r
+ cleanup_nssm_service(service);\r
+ return 4;\r
+\r
+ case 6:\r
+ popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_EDIT_PARAMETERS_FAILED);\r
+ cleanup_nssm_service(service);\r
+ return 6;\r
+ }\r
+\r
+ popup_message(MB_OK, NSSM_MESSAGE_SERVICE_EDITED, service->name);\r
+ cleanup_nssm_service(service);\r
+ return 0;\r
+}\r
+\r
static TCHAR *browse_filter(int message) {\r
switch (message) {\r
case NSSM_GUI_BROWSE_FILTER_APPLICATIONS: return _T("*.exe;*.bat;*.cmd");\r
\r
/* Install/remove dialogue callback */\r
INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {\r
+ nssm_service_t *service;\r
+\r
switch (message) {\r
/* Creating the dialogue */\r
case WM_INITDIALOG:\r
+ service = (nssm_service_t *) l;\r
+\r
SetFocus(GetDlgItem(window, IDC_NAME));\r
\r
HWND tabs;\r
ZeroMemory(&tab, sizeof(tab));\r
tab.mask = TCIF_TEXT;\r
\r
+ selected_tab = 0;\r
+\r
/* Application tab. */\r
- tab.pszText = message_string(NSSM_GUI_TAB_APPLICATION);\r
+ if (service->native) tab.pszText = message_string(NSSM_GUI_TAB_NATIVE);\r
+ else tab.pszText = message_string(NSSM_GUI_TAB_APPLICATION);\r
tab.cchTextMax = (int) _tcslen(tab.pszText);\r
SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_APPLICATION, (LPARAM) &tab);\r
- tablist[NSSM_TAB_APPLICATION] = CreateDialog(0, MAKEINTRESOURCE(IDD_APPLICATION), window, tab_dlg);\r
+ if (service->native) {\r
+ tablist[NSSM_TAB_APPLICATION] = CreateDialog(0, MAKEINTRESOURCE(IDD_NATIVE), window, tab_dlg);\r
+ EnableWindow(tablist[NSSM_TAB_APPLICATION], 0);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_APPLICATION], IDC_PATH), 0);\r
+ }\r
+ else tablist[NSSM_TAB_APPLICATION] = CreateDialog(0, MAKEINTRESOURCE(IDD_APPLICATION), window, tab_dlg);\r
ShowWindow(tablist[NSSM_TAB_APPLICATION], SW_SHOW);\r
\r
/* Details tab. */\r
CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
set_logon_enabled(0);\r
\r
+ /* Remaining tabs are only for services we manage. */\r
+ if (service->native) return 1;\r
+\r
/* Shutdown tab. */\r
tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN);\r
tab.cchTextMax = (int) _tcslen(tab.pszText);\r
tablist[NSSM_TAB_ENVIRONMENT] = CreateDialog(0, MAKEINTRESOURCE(IDD_ENVIRONMENT), window, tab_dlg);\r
ShowWindow(tablist[NSSM_TAB_ENVIRONMENT], SW_HIDE);\r
\r
- selected_tab = 0;\r
-\r
return 1;\r
\r
/* Tab change. */\r
selection = (int) SendMessage(tabs, TCM_GETCURSEL, 0, 0);\r
if (selection != selected_tab) {\r
ShowWindow(tablist[selected_tab], SW_HIDE);\r
- /*\r
- XXX: Sets focus to the service name which isn't ideal but is\r
- better than leaving it in another tab.\r
- */\r
ShowWindow(tablist[selection], SW_SHOWDEFAULT);\r
- SetFocus(tablist[selection]);\r
+ SetFocus(GetDlgItem(window, IDOK));\r
selected_tab = selection;\r
}\r
return 1;\r
switch (LOWORD(w)) {\r
/* OK button */\r
case IDOK:\r
- if (! install(window)) PostQuitMessage(0);\r
+ if ((int) GetWindowLongPtr(window, GWLP_USERDATA) == IDD_EDIT) {\r
+ if (! edit(window, (nssm_service_t *) GetWindowLongPtr(window, DWLP_USER))) PostQuitMessage(0);\r
+ }\r
+ else if (! install(window)) PostQuitMessage(0);\r
break;\r
\r
/* Cancel button */\r
\r
int nssm_gui(int, nssm_service_t *);\r
void centre_window(HWND);\r
+int configure(HWND, nssm_service_t *, nssm_service_t *);\r
int install(HWND);\r
int remove(HWND);\r
+int edit(HWND, nssm_service_t *);\r
void browse(HWND);\r
INT_PTR CALLBACK nssm_dlg(HWND, UINT, WPARAM, LPARAM);\r
\r
nssm install <servicename> <app> [<args>]
+To show service editing GUI:
+
+ nssm edit <servicename>
+
To show service removal GUI:
nssm remove [<servicename>]
L'installazione di un servizio richiede privilegi di amministratore.
.
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_EDIT
+Severity = Informational
+Language = English
+Administrator access is needed to edit a service.
+.
+Language = French
+Les droits d'administrateur sont requis pour éditer un service.
+.
+Language = Italian
+L'edizione di un servizio richiede privilegi di amministratore.
+.
+
MessageId = +1
SymbolicName = NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_REMOVE
Severity = Informational
Errore apertura Service Manager!
.
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_QUERYSERVICECONFIG_FAILED
+Severity = Informational
+Language = English
+Error querying service %s!
+QueryServiceConfig(): %s%0
+.
+Language = French
+Error querying service %s!
+QueryServiceConfig(): %s%0
+.
+Language = Italian
+Error querying service %s!
+QueryServiceConfig(): %s%0
+.
+
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED
+Severity = Informational
+Language = English
+Error querying service %s!
+QueryServiceConfig2(%s): %s%0
+.
+Language = French
+Error querying service %s!
+QueryServiceConfig2(%s): %s%0
+.
+Language = Italian
+Error querying service %s!
+QueryServiceConfig2(%s): %s%0
+.
+
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_INVALID_SERVICE
+Severity = Informational
+Language = English
+Service "%s" is not a valid %s service!
+Executable is %s%0
+.
+Language = French
+Service "%s" is not a valid %s service!
+Executable is %s%0
+.
+Language = Italian
+Service "%s" is not a valid %s service!
+Executable is %s%0
+.
+
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_CANNOT_EDIT
+Severity = Informational
+Language = English
+Service "%s" is not a %s service!
+.
+Language = French
+Service "%s" is not a %s service!
+.
+Language = Italian
+Service "%s" is not a %s service!
+.
+
MessageId = +1
SymbolicName = NSSM_MESSAGE_PATH_TOO_LONG
Severity = Informational
Errore creazione servizio!
.
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED
+Severity = Informational
+Language = English
+Error editing service!
+ChangeServiceConfig(): %s%0
+.
+Language = French
+Erreur à l'édition du service!
+ChangeServiceConfig(): %s%0
+.
+Language = Italian
+Errore edizione servizio!
+ChangeServiceConfig(): %s%0
+.
+
MessageId = +1
SymbolicName = NSSM_MESSAGE_CREATE_PARAMETERS_FAILED
Severity = Informational
Servizio "%s" rimosso correttamente!
.
+MessageId = +1
+SymbolicName = NSSM_MESSAGE_SERVICE_EDITED
+Severity = Informational
+Language = English
+Service "%s" edited successfully!
+.
+Language = French
+Le service "%s" a été édité avec succès!
+.
+Language = Italian
+Servizio "%s" edizione correttamente!
+.
+
MessageId = +1
SymbolicName = NSSM_GUI_CREATEDIALOG_FAILED
Severity = Informational
Eliminazione servizio in corso...
.
+MessageId = +1
+SymbolicName = NSSM_GUI_EDIT_PARAMETERS_FAILED
+Severity = Informational
+Language = English
+Couldn't set startup parameters for the service!
+.
+Language = French
+Impossible de régler les paramètres de démarrage pour le service!
+.
+Language = Italian
+Impossibile impostare i parametri di avvio per il servizio!
+.
+
MessageId = +1
SymbolicName = NSSM_GUI_ASK_REMOVE_SERVICE
Severity = Informational
Applicazione%0
.
+MessageId = +1
+SymbolicName = NSSM_GUI_TAB_NATIVE
+Severity = Informational
+Language = English
+Service%0
+.
+Language = French
+Service%0
+.
+Language = Italian
+Servizio%0
+.
+
MessageId = +1
SymbolicName = NSSM_GUI_TAB_DETAILS
Severity = Informational
Fake crash (pre-Vista)%0
.
+MessageId = +1
+SymbolicName = NSSM_GUI_WARN_STDIO
+Severity = Informational
+Language = English
+The service is configured with I/O redirection settings which cannot be
+represented by this GUI's simplified set of options. Check the registry
+after editing the service to confirm its I/O redirection settings.
+.
+Language = French
+The service is configured with I/O redirection settings which cannot be
+represented by this GUI's simplified set of options. Check the registry
+after editing the service to confirm its I/O redirection settings.
+.
+Language = Italian
+The service is configured with I/O redirection settings which cannot be
+represented by this GUI's simplified set of options. Check the registry
+after editing the service to confirm its I/O redirection settings.
+.
+
+MessageId = +1
+SymbolicName = NSSM_GUI_WARN_ROTATE_BYTES
+Severity = Informational
+Language = English
+The service is configured with a 64-bit file size threshold for file
+rotation. This GUI can only display 32-bit settings. Check the registry
+after editing the service to confirm its file rotation settings.
+.
+Language = French
+The service is configured with a 64-bit file size threshold for file
+rotation. This GUI can only display 32-bit settings. Check the registry
+after editing the service to confirm its file rotation settings.
+.
+Language = Italian
+The service is configured with a 64-bit file size threshold for file
+rotation. This GUI can only display 32-bit settings. Check the registry
+after editing the service to confirm its file rotation settings.
+.
+
+MessageId = +1
+SymbolicName = NSSM_GUI_WARN_ENVIRONMENT
+Severity = Informational
+Language = English
+The service is configured with a srvany-compatible environment block
+for the application as well as an extra environment block. This GUI
+can only display one such block. Editing the service will result in
+one of the environment blocks being deleted.
+.
+Language = French
+The service is configured with a srvany-compatible environment block
+for the application as well as an extra environment block. This GUI
+can only display one such block. Editing the service will result in
+one of the environment blocks being deleted.
+.
+Language = Italian
+The service is configured with a srvany-compatible environment block
+for the application as well as an extra environment block. This GUI
+can only display one such block. Editing the service will result in
+one of the environment blocks being deleted.
+.
+
MessageId = 1001
SymbolicName = NSSM_EVENT_DISPATCHER_FAILED
Severity = Error
\r
/* Elevate */\r
if (argc > 1) {\r
- /* Valid commands are install or remove */\r
+ /* Valid commands are install, edit or remove */\r
if (str_equiv(argv[1], _T("install"))) {\r
if (! is_admin) {\r
print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);\r
}\r
exit(pre_install_service(argc - 2, argv + 2));\r
}\r
+ if (str_equiv(argv[1], _T("edit"))) {\r
+ if (! is_admin) {\r
+ print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_EDIT);\r
+ exit(100);\r
+ }\r
+ exit(pre_edit_service(argc - 2, argv + 2));\r
+ }\r
if (str_equiv(argv[1], _T("remove"))) {\r
if (! is_admin) {\r
print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_REMOVE);\r
\r
int str_equiv(const TCHAR *, const TCHAR *);\r
void strip_basename(TCHAR *);\r
+int usage(int);\r
\r
#define NSSM _T("nssm")\r
#define NSSM_VERSION _T("2.21")\r
EDITTEXT IDC_NAME,59,7,87,14,ES_AUTOHSCROLL\r
END\r
\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+IDD_EDIT DIALOG 0, 0, 286, 126\r
+STYLE DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU\r
+CAPTION "NSSM service editor"\r
+FONT 8, "MS Sans Serif"\r
+{\r
+ CONTROL "", IDC_TAB1, WC_TABCONTROL, 0, 7, 7, 269, 93\r
+ LTEXT "Service name:", IDC_STATIC, 7, 106, 52, 8, SS_LEFT\r
+ EDITTEXT IDC_NAME, 64, 104, 98, 12, ES_AUTOHSCROLL\r
+ DEFPUSHBUTTON "Edit service", IDOK, 172, 104, 50, 14\r
+ PUSHBUTTON "Cancel", IDCANCEL, 227, 104, 50, 14\r
+}\r
+\r
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
IDD_APPLICATION DIALOG 9, 20, 261, 75\r
STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
EDITTEXT IDC_FLAGS, 70, 48, 184, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
}\r
\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+IDD_NATIVE DIALOG 9, 20, 261, 75\r
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
+FONT 8, "MS Sans Serif"\r
+{\r
+ GROUPBOX "Service", IDC_STATIC, 7, 7, 251, 68\r
+ LTEXT "Image path:", IDC_STATIC, 13, 18, 53, 8, SS_LEFT\r
+ EDITTEXT IDC_PATH, 70, 16, 184, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
+}\r
+\r
\r
\r
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
EDITTEXT IDC_NAME,43,7,90,14,ES_AUTOHSCROLL\r
END\r
\r
+LANGUAGE LANG_FRENCH, SUBLANG_FRENCH\r
+IDD_EDIT DIALOG 0, 0, 282, 126\r
+STYLE DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU\r
+CAPTION "Edition d'un service NSSM"\r
+FONT 8, "MS Sans Serif"\r
+{\r
+ CONTROL "", IDC_TAB1, WC_TABCONTROL, 0, 7, 7, 269, 93\r
+ LTEXT "Nom du service:", IDC_STATIC, 7, 106, 52, 8, SS_LEFT\r
+ EDITTEXT IDC_NAME, 64, 104, 98, 12, ES_AUTOHSCROLL\r
+ DEFPUSHBUTTON "Editer le service", IDOK, 172, 106, 50, 14\r
+ PUSHBUTTON "Anuller", IDCANCEL, 227, 106, 50, 14\r
+}\r
+\r
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH\r
IDD_APPLICATION DIALOG 9, 20, 261, 75\r
STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
EDITTEXT IDC_FLAGS, 80, 45, 174, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
}\r
\r
+LANGUAGE LANG_FRENCH, SUBLANG_FRENCH\r
+IDD_NATIVE DIALOG 9, 20, 261, 75\r
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
+FONT 8, "MS Sans Serif"\r
+{\r
+ GROUPBOX "Service", IDC_STATIC, 7, 7, 251, 68\r
+ LTEXT "Chemin:", IDC_STATIC, 13, 18, 53, 8, SS_LEFT\r
+ EDITTEXT IDC_PATH, 70, 16, 184, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
+}\r
+\r
\r
/////////////////////////////////////////////////////////////////////////////\r
//\r
EDITTEXT IDC_NAME,59,7,87,14,ES_AUTOHSCROLL\r
END\r
\r
+LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN\r
+IDD_EDIT DIALOG 0, 0, 282, 126\r
+STYLE DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_POPUP | WS_SYSMENU\r
+CAPTION "NSSM - Edizione Servizio"\r
+FONT 8, "MS Sans Serif"\r
+{\r
+ CONTROL "", IDC_TAB1, WC_TABCONTROL, 0, 7, 7, 269, 93\r
+ LTEXT "Nome servizio:", IDC_STATIC, 7, 106, 52, 8, SS_LEFT\r
+ EDITTEXT IDC_NAME, 64, 104, 98, 12, ES_AUTOHSCROLL\r
+ DEFPUSHBUTTON "Edita servizio", IDOK, 172, 106, 50, 14\r
+ PUSHBUTTON "Anulla", IDCANCEL, 227, 106, 50, 14\r
+}\r
+\r
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN\r
IDD_APPLICATION DIALOG 9, 20, 261, 75\r
STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
EDITTEXT IDC_FLAGS, 70, 46, 184, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
}\r
\r
+LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN\r
+IDD_NATIVE DIALOG 9, 20, 261, 75\r
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
+FONT 8, "MS Sans Serif"\r
+{\r
+ GROUPBOX "Servizio", IDC_STATIC, 7, 7, 251, 68\r
+ LTEXT "Path:", IDC_STATIC, 13, 18, 53, 8, SS_LEFT\r
+ EDITTEXT IDC_PATH, 70, 16, 184, 12, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
+}\r
+\r
\r
/////////////////////////////////////////////////////////////////////////////\r
//\r
return 0;\r
}\r
\r
-int create_parameters(nssm_service_t *service) {\r
+int create_parameters(nssm_service_t *service, bool editing) {\r
/* Get registry */\r
TCHAR registry[KEY_LENGTH];\r
if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, NSSM_REGISTRY, service->name) < 0) {\r
/* Other non-default parameters. May fail. */\r
unsigned long stop_method_skip = ~service->stop_method;\r
if (stop_method_skip) set_number(key, NSSM_REG_STOP_METHOD_SKIP, stop_method_skip);\r
- if (service->default_exit_action < NSSM_NUM_EXIT_ACTIONS) create_exit_action(service->name, exit_action_strings[service->default_exit_action]);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_STOP_METHOD_SKIP);\r
+ if (service->default_exit_action < NSSM_NUM_EXIT_ACTIONS) create_exit_action(service->name, exit_action_strings[service->default_exit_action], editing);\r
if (service->throttle_delay != NSSM_RESET_THROTTLE_RESTART) set_number(key, NSSM_REG_THROTTLE, service->throttle_delay);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_THROTTLE);\r
if (service->kill_console_delay != NSSM_KILL_CONSOLE_GRACE_PERIOD) set_number(key, NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, service->kill_console_delay);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_KILL_CONSOLE_GRACE_PERIOD);\r
if (service->kill_window_delay != NSSM_KILL_WINDOW_GRACE_PERIOD) set_number(key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD, service->kill_window_delay);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD);\r
if (service->kill_threads_delay != NSSM_KILL_THREADS_GRACE_PERIOD) set_number(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, service->kill_threads_delay);\r
- if (service->stdin_path[0]) {\r
- set_expand_string(key, NSSM_REG_STDIN, service->stdin_path);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD);\r
+ if (service->stdin_path[0] || editing) {\r
+ if (service->stdin_path[0]) set_expand_string(key, NSSM_REG_STDIN, service->stdin_path);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_STDIN);\r
if (service->stdin_sharing != NSSM_STDIN_SHARING) set_createfile_parameter(key, NSSM_REG_STDIN, NSSM_REG_STDIO_SHARING, service->stdin_sharing);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDIN, NSSM_REG_STDIO_SHARING);\r
if (service->stdin_disposition != NSSM_STDIN_DISPOSITION) set_createfile_parameter(key, NSSM_REG_STDIN, NSSM_REG_STDIO_DISPOSITION, service->stdin_disposition);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDIN, NSSM_REG_STDIO_DISPOSITION);\r
if (service->stdin_flags != NSSM_STDIN_FLAGS) set_createfile_parameter(key, NSSM_REG_STDIN, NSSM_REG_STDIO_FLAGS, service->stdin_flags);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDIN, NSSM_REG_STDIO_FLAGS);\r
}\r
- if (service->stdout_path[0]) {\r
- set_expand_string(key, NSSM_REG_STDOUT, service->stdout_path);\r
+ if (service->stdout_path[0] || editing) {\r
+ if (service->stdout_path[0]) set_expand_string(key, NSSM_REG_STDOUT, service->stdout_path);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_STDOUT);\r
if (service->stdout_sharing != NSSM_STDOUT_SHARING) set_createfile_parameter(key, NSSM_REG_STDOUT, NSSM_REG_STDIO_SHARING, service->stdout_sharing);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDOUT, NSSM_REG_STDIO_SHARING);\r
if (service->stdout_disposition != NSSM_STDOUT_DISPOSITION) set_createfile_parameter(key, NSSM_REG_STDOUT, NSSM_REG_STDIO_DISPOSITION, service->stdout_disposition);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDOUT, NSSM_REG_STDIO_DISPOSITION);\r
if (service->stdout_flags != NSSM_STDOUT_FLAGS) set_createfile_parameter(key, NSSM_REG_STDOUT, NSSM_REG_STDIO_FLAGS, service->stdout_flags);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDOUT, NSSM_REG_STDIO_FLAGS);\r
}\r
- if (service->stderr_path[0]) {\r
- set_expand_string(key, NSSM_REG_STDERR, service->stderr_path);\r
+ if (service->stderr_path[0] || editing) {\r
+ if (service->stderr_path[0]) set_expand_string(key, NSSM_REG_STDERR, service->stderr_path);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_STDERR);\r
if (service->stderr_sharing != NSSM_STDERR_SHARING) set_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_SHARING, service->stderr_sharing);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_SHARING);\r
if (service->stderr_disposition != NSSM_STDERR_DISPOSITION) set_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_DISPOSITION, service->stderr_disposition);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_DISPOSITION);\r
if (service->stderr_flags != NSSM_STDERR_FLAGS) set_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_FLAGS, service->stderr_flags);\r
+ else if (editing) delete_createfile_parameter(key, NSSM_REG_STDERR, NSSM_REG_STDIO_FLAGS);\r
}\r
if (service->rotate_files) set_number(key, NSSM_REG_ROTATE, 1);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_ROTATE);\r
if (service->rotate_seconds) set_number(key, NSSM_REG_ROTATE_SECONDS, service->rotate_seconds);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_ROTATE_SECONDS);\r
if (service->rotate_bytes_low) set_number(key, NSSM_REG_ROTATE_BYTES_LOW, service->rotate_bytes_low);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_ROTATE_BYTES_LOW);\r
if (service->rotate_bytes_high) set_number(key, NSSM_REG_ROTATE_BYTES_HIGH, service->rotate_bytes_high);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_ROTATE_BYTES_HIGH);\r
\r
/* Environment */\r
if (service->env) {\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);\r
}\r
}\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_ENV);\r
if (service->env_extra) {\r
if (RegSetValueEx(key, NSSM_REG_ENV_EXTRA, 0, REG_MULTI_SZ, (const unsigned char *) service->env_extra, (unsigned long) service->env_extralen * sizeof(TCHAR)) != ERROR_SUCCESS) {\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV_EXTRA, error_string(GetLastError()), 0);\r
}\r
}\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_ENV_EXTRA);\r
\r
/* Close registry. */\r
RegCloseKey(key);\r
return 0;\r
}\r
\r
-int create_exit_action(TCHAR *service_name, const TCHAR *action_string) {\r
+int create_exit_action(TCHAR *service_name, const TCHAR *action_string, bool editing) {\r
/* Get registry */\r
TCHAR registry[KEY_LENGTH];\r
if (_sntprintf_s(registry, _countof(registry), _TRUNCATE, NSSM_REGISTRY _T("\\%s"), service_name, NSSM_REG_EXIT) < 0) {\r
}\r
\r
/* Do nothing if the key already existed */\r
- if (disposition == REG_OPENED_EXISTING_KEY) {\r
+ if (disposition == REG_OPENED_EXISTING_KEY && ! editing) {\r
RegCloseKey(key);\r
return 0;\r
}\r
override_milliseconds(service->name, key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD, &service->kill_window_delay, NSSM_KILL_WINDOW_GRACE_PERIOD, NSSM_EVENT_BOGUS_KILL_WINDOW_GRACE_PERIOD);\r
override_milliseconds(service->name, key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, &service->kill_threads_delay, NSSM_KILL_THREADS_GRACE_PERIOD, NSSM_EVENT_BOGUS_KILL_THREADS_GRACE_PERIOD);\r
\r
+ /* Try to get default exit action. */\r
+ bool default_action;\r
+ service->default_exit_action = NSSM_EXIT_RESTART;\r
+ TCHAR action_string[ACTION_LEN];\r
+ if (! get_exit_action(service->name, 0, action_string, &default_action)) {\r
+ for (int i = 0; exit_action_strings[i]; i++) {\r
+ if (! _tcsnicmp((const TCHAR *) action_string, exit_action_strings[i], ACTION_LEN)) {\r
+ service->default_exit_action = i;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
/* Close registry */\r
RegCloseKey(key);\r
\r
#define NSSM_STDIO_LENGTH 29\r
\r
int create_messages();\r
-int create_parameters(nssm_service_t *);\r
-int create_exit_action(TCHAR *, const TCHAR *);\r
+int create_parameters(nssm_service_t *, bool);\r
+int create_exit_action(TCHAR *, const TCHAR *, bool);\r
int set_environment(TCHAR *, HKEY, TCHAR *, TCHAR **, unsigned long *);\r
int expand_parameter(HKEY, TCHAR *, TCHAR *, unsigned long, bool, bool);\r
int expand_parameter(HKEY, TCHAR *, TCHAR *, unsigned long, bool);\r
#define IDI_NSSM 101\r
#define IDD_INSTALL 102\r
#define IDD_REMOVE 103\r
-#define IDD_APPLICATION 104\r
-#define IDD_DETAILS 105\r
-#define IDD_LOGON 106\r
-#define IDD_IO 107\r
-#define IDD_ROTATION 108\r
-#define IDD_APPEXIT 109\r
-#define IDD_SHUTDOWN 110\r
-#define IDD_ENVIRONMENT 111\r
+#define IDD_EDIT 104\r
+#define IDD_APPLICATION 105\r
+#define IDD_DETAILS 106\r
+#define IDD_LOGON 107\r
+#define IDD_IO 108\r
+#define IDD_ROTATION 109\r
+#define IDD_APPEXIT 110\r
+#define IDD_SHUTDOWN 111\r
+#define IDD_ENVIRONMENT 112\r
+#define IDD_NATIVE 113\r
#define IDC_PATH 1000\r
#define IDC_TAB1 1001\r
#define IDC_CANCEL 1002\r
// \r
#ifdef APSTUDIO_INVOKED\r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
-#define _APS_NEXT_RESOURCE_VALUE 112\r
+#define _APS_NEXT_RESOURCE_VALUE 114\r
#define _APS_NEXT_COMMAND_VALUE 40001\r
#define _APS_NEXT_CONTROL_VALUE 1040\r
#define _APS_NEXT_SYMED_VALUE 101\r
#include "nssm.h"\r
\r
+extern const TCHAR *exit_action_strings[];\r
+\r
bool is_admin;\r
bool use_critical_section;\r
\r
return ret;\r
}\r
\r
+/* About to edit the service. */\r
+int pre_edit_service(int argc, TCHAR **argv) {\r
+ /* Require service name. */\r
+ if (argc < 1) return usage(1);\r
+\r
+ nssm_service_t *service = alloc_nssm_service();\r
+ _sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), argv[0]);\r
+\r
+ /* Open service manager */\r
+ SC_HANDLE services = open_service_manager();\r
+ if (! services) {\r
+ print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
+ return 2;\r
+ }\r
+\r
+ /* Try to open the service */\r
+ service->handle = OpenService(services, service->name, SC_MANAGER_ALL_ACCESS);\r
+ if (! service->handle) {\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_OPENSERVICE_FAILED);\r
+ return 3;\r
+ }\r
+\r
+ /* Get system details. */\r
+ unsigned long bufsize;\r
+ unsigned long error;\r
+ QUERY_SERVICE_CONFIG *qsc;\r
+\r
+ QueryServiceConfig(service->handle, 0, 0, &bufsize);\r
+ error = GetLastError();\r
+ if (error == ERROR_INSUFFICIENT_BUFFER) {\r
+ qsc = (QUERY_SERVICE_CONFIG *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufsize);\r
+ if (! qsc) {\r
+ print_message(stderr, NSSM_EVENT_OUT_OF_MEMORY, _T("QUERY_SERVICE_CONFIG"), _T("pre_edit_service()"), 0);\r
+ return 4;\r
+ }\r
+ }\r
+ else {\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG_FAILED, service->name, error_string(error), 0);\r
+ return 4;\r
+ }\r
+\r
+ if (! QueryServiceConfig(service->handle, qsc, bufsize, &bufsize)) {\r
+ HeapFree(GetProcessHeap(), 0, qsc);\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG_FAILED, service->name, error_string(GetLastError()), 0);\r
+ return 4;\r
+ }\r
+\r
+ service->type = qsc->dwServiceType;\r
+ if (! (service->type & SERVICE_WIN32_OWN_PROCESS)) {\r
+ HeapFree(GetProcessHeap(), 0, qsc);\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_CANNOT_EDIT, service->name, _T("SERVICE_WIN32_OWN_PROCESS"), 0);\r
+ return 3;\r
+ }\r
+\r
+ switch (qsc->dwStartType) {\r
+ case SERVICE_DEMAND_START: service->startup = NSSM_STARTUP_MANUAL; break;\r
+ case SERVICE_DISABLED: service->startup = NSSM_STARTUP_DISABLED; break;\r
+ default: service->startup = NSSM_STARTUP_AUTOMATIC;\r
+ }\r
+ if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) {\r
+ size_t len = _tcslen(qsc->lpServiceStartName);\r
+ service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(TCHAR));\r
+ if (service->username) {\r
+ memmove(service->username, qsc->lpServiceStartName, (len + 1) * sizeof(TCHAR));\r
+ service->usernamelen = (unsigned long) len;\r
+ }\r
+ else {\r
+ HeapFree(GetProcessHeap(), 0, qsc);\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_EVENT_OUT_OF_MEMORY, _T("username"), _T("pre_edit_service()"));\r
+ return 4;\r
+ }\r
+ }\r
+ _sntprintf_s(service->displayname, _countof(service->displayname), _TRUNCATE, _T("%s"), qsc->lpDisplayName);\r
+\r
+ /* Remember the executable in case it isn't NSSM. */\r
+ _sntprintf_s(service->image, _countof(service->image), _TRUNCATE, _T("%s"), qsc->lpBinaryPathName);\r
+ HeapFree(GetProcessHeap(), 0, qsc);\r
+\r
+ /* Get extended system details. */\r
+ if (service->startup == NSSM_STARTUP_AUTOMATIC) {\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
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_EVENT_OUT_OF_MEMORY, _T("SERVICE_DELAYED_AUTO_START_INFO"), _T("pre_edit_service()"));\r
+ return 5;\r
+ }\r
+\r
+ if (QueryServiceConfig2(service->handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (unsigned char *) info, bufsize, &bufsize)) {\r
+ if (info->fDelayedAutostart) service->startup = NSSM_STARTUP_DELAYED;\r
+ }\r
+ else {\r
+ error = GetLastError();\r
+ if (error != ERROR_INVALID_LEVEL) {\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error));\r
+ return 5;\r
+ }\r
+ }\r
+ }\r
+ else if (error != ERROR_INVALID_LEVEL) {\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_DELAYED_AUTO_START_INFO"), error_string(error));\r
+ return 5;\r
+ }\r
+ }\r
+\r
+ QueryServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, 0, 0, &bufsize);\r
+ error = GetLastError();\r
+ if (error == ERROR_INSUFFICIENT_BUFFER) {\r
+ SERVICE_DESCRIPTION *description = (SERVICE_DESCRIPTION *) HeapAlloc(GetProcessHeap(), 0, bufsize);\r
+ if (! description) {\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_EVENT_OUT_OF_MEMORY, _T("SERVICE_CONFIG_DESCRIPTION"), _T("pre_edit_service()"));\r
+ return 6;\r
+ }\r
+\r
+ if (QueryServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, (unsigned char *) description, bufsize, &bufsize)) {\r
+ if (description->lpDescription) _sntprintf_s(service->description, _countof(service->description), _TRUNCATE, _T("%s"), description->lpDescription);\r
+ HeapFree(GetProcessHeap(), 0, description);\r
+ }\r
+ else {\r
+ HeapFree(GetProcessHeap(), 0, description);\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error));\r
+ return 6;\r
+ }\r
+ }\r
+ else {\r
+ CloseHandle(service->handle);\r
+ CloseServiceHandle(services);\r
+ print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error));\r
+ return 6;\r
+ }\r
+\r
+ /* Get NSSM details. */\r
+ get_parameters(service, 0);\r
+\r
+ CloseServiceHandle(services);\r
+\r
+ if (! service->exe[0]) {\r
+ print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE, service->name, NSSM, service->image);\r
+ service->native = true;\r
+ }\r
+\r
+ nssm_gui(IDD_EDIT, service);\r
+\r
+ return 0;\r
+}\r
+\r
/* About to remove the service */\r
int pre_remove_service(int argc, TCHAR **argv) {\r
nssm_service_t *service = alloc_nssm_service();\r
}\r
\r
/* Get path of this program */\r
- TCHAR command[MAX_PATH];\r
- GetModuleFileName(0, command, _countof(command));\r
+ GetModuleFileName(0, service->image, _countof(service->image));\r
+\r
+ /* Create the service - settings will be changed in edit_service() */\r
+ service->handle = CreateService(services, service->name, service->name, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, service->image, 0, 0, 0, 0, 0);\r
+ if (! service->handle) {\r
+ print_message(stderr, NSSM_MESSAGE_CREATESERVICE_FAILED);\r
+ CloseServiceHandle(services);\r
+ return 5;\r
+ }\r
+\r
+ if (edit_service(service, false)) {\r
+ DeleteService(service->handle);\r
+ CloseServiceHandle(services);\r
+ return 6;\r
+ }\r
+\r
+ print_message(stdout, NSSM_MESSAGE_SERVICE_INSTALLED, service->name);\r
+\r
+ /* Cleanup */\r
+ CloseServiceHandle(services);\r
+\r
+ return 0;\r
+}\r
+\r
+/* Edit the service. */\r
+int edit_service(nssm_service_t *service, bool editing) {\r
+ if (! service) return 1;\r
\r
/*\r
The only two valid flags for service type are SERVICE_WIN32_OWN_PROCESS\r
/* Display name. */\r
if (! service->displayname[0]) _sntprintf_s(service->displayname, _countof(service->displayname), _TRUNCATE, _T("%s"), service->name);\r
\r
- /* Create the service */\r
- service->handle = CreateService(services, service->name, service->displayname, SC_MANAGER_ALL_ACCESS, service->type, startup, SERVICE_ERROR_NORMAL, command, 0, 0, 0, service->username, service->password);\r
- if (! service->handle) {\r
- print_message(stderr, NSSM_MESSAGE_CREATESERVICE_FAILED);\r
- CloseServiceHandle(services);\r
+ /*\r
+ Username must be NULL if we aren't changing or an account name.\r
+ We must explicitly user LOCALSYSTEM to change it when we are editing.\r
+ Password must be NULL if we aren't changing, a password or "".\r
+ Empty passwords are valid but we won't allow them in the GUI.\r
+ */\r
+ TCHAR *username = 0;\r
+ TCHAR *password = 0;\r
+ if (service->usernamelen) {\r
+ username = service->username;\r
+ if (service->passwordlen) password = service->password;\r
+ else password = _T("");\r
+ }\r
+ else if (editing) username = NSSM_LOCALSYSTEM_ACCOUNT;\r
+\r
+ if (! ChangeServiceConfig(service->handle, service->type, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, service->displayname)) {\r
+ print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));\r
return 5;\r
}\r
\r
- if (service->description[0]) {\r
+ if (service->description[0] || editing) {\r
SERVICE_DESCRIPTION description;\r
ZeroMemory(&description, sizeof(description));\r
- description.lpDescription = service->description;\r
+ if (service->description[0]) description.lpDescription = service->description;\r
+ else description.lpDescription = 0;\r
if (! ChangeServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, &description)) {\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DESCRIPTION_FAILED, service->name, error_string(GetLastError()), 0);\r
}\r
}\r
\r
- if (service->startup == NSSM_STARTUP_DELAYED) {\r
- SERVICE_DELAYED_AUTO_START_INFO delayed;\r
- ZeroMemory(&delayed, sizeof(delayed));\r
- delayed.fDelayedAutostart = 1;\r
- /* Delayed startup isn't supported until Vista. */\r
- if (! ChangeServiceConfig2(service->handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {\r
- unsigned long error = GetLastError();\r
- /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */\r
- if (error != ERROR_INVALID_LEVEL) {\r
- log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service->name, error_string(error), 0);\r
- }\r
+ SERVICE_DELAYED_AUTO_START_INFO delayed;\r
+ ZeroMemory(&delayed, sizeof(delayed));\r
+ if (service->startup == NSSM_STARTUP_DELAYED) delayed.fDelayedAutostart = 1;\r
+ else delayed.fDelayedAutostart = 0;\r
+ /* Delayed startup isn't supported until Vista. */\r
+ if (! ChangeServiceConfig2(service->handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {\r
+ unsigned long error = GetLastError();\r
+ /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */\r
+ if (error != ERROR_INVALID_LEVEL) {\r
+ log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service->name, error_string(error), 0);\r
}\r
}\r
\r
- /* Now we need to put the parameters into the registry */\r
- if (create_parameters(service)) {\r
- print_message(stderr, NSSM_MESSAGE_CREATE_PARAMETERS_FAILED);\r
- DeleteService(service->handle);\r
- CloseServiceHandle(services);\r
- return 6;\r
- }\r
-\r
- set_service_recovery(service);\r
-\r
- print_message(stdout, NSSM_MESSAGE_SERVICE_INSTALLED, service->name);\r
+ /* Don't mess with parameters which aren't ours. */\r
+ if (! service->native) {\r
+ /* Now we need to put the parameters into the registry */\r
+ if (create_parameters(service, editing)) {\r
+ print_message(stderr, NSSM_MESSAGE_CREATE_PARAMETERS_FAILED);\r
+ return 6;\r
+ }\r
\r
- /* Cleanup */\r
- CloseServiceHandle(services);\r
+ set_service_recovery(service);\r
+ }\r
\r
return 0;\r
}\r
\r
if (is_admin) {\r
/* Try to create the exit action parameters; we don't care if it fails */\r
- create_exit_action(service->name, exit_action_strings[0]);\r
+ create_exit_action(service->name, exit_action_strings[0], false);\r
\r
SC_HANDLE services = open_service_manager();\r
if (services) {\r
\r
#define ACTION_LEN 16\r
\r
+#define NSSM_LOCALSYSTEM_ACCOUNT _T("LocalSystem")\r
+\r
typedef struct {\r
+ bool native;\r
TCHAR name[SERVICE_NAME_LENGTH];\r
TCHAR displayname[SERVICE_DISPLAYNAME_LENGTH];\r
TCHAR description[VALUE_LENGTH];\r
TCHAR *password;\r
size_t passwordlen;\r
unsigned long type;\r
+ TCHAR image[MAX_PATH];\r
TCHAR exe[EXE_LENGTH];\r
TCHAR flags[VALUE_LENGTH];\r
TCHAR dir[MAX_PATH];\r
SC_HANDLE open_service_manager();\r
int pre_install_service(int, TCHAR **);\r
int pre_remove_service(int, TCHAR **);\r
+int pre_edit_service(int, TCHAR **);\r
int install_service(nssm_service_t *);\r
int remove_service(nssm_service_t *);\r
+int edit_service(nssm_service_t *, bool);\r
void set_service_recovery(nssm_service_t *);\r
int monitor_service(nssm_service_t *);\r
int start_service(nssm_service_t *);\r