From a02019297db435c1de6846fd0387a53335f4289e Mon Sep 17 00:00:00 2001 From: Iain Patterson Date: Sat, 21 Dec 2013 16:10:33 +0000 Subject: [PATCH] Set service details in the GUI. The GUI can now set the service display name, description and startup type. --- ChangeLog.txt | 3 ++ README.txt | 3 ++ gui.cpp | 38 ++++++++++++++++- messages.mc | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- nssm.h | 6 +++ nssm.rc | 14 +++++++ resource.h | 18 ++++---- service.cpp | 38 ++++++++++++++++- service.h | 4 ++ 9 files changed, 243 insertions(+), 12 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index e73a9aa..8bd2dd0 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -6,6 +6,9 @@ Changes since 2.21 * Unqualified path names are now relative to the application startup directory when redirecting I/O. + * NSSM can now set the service display name, description + and startup type. + Changes since 2.20 ------------------ * Services installed from the GUI no longer have incorrect diff --git a/README.txt b/README.txt index 366e6f3..8be1383 100644 --- a/README.txt +++ b/README.txt @@ -55,6 +55,9 @@ AppEnvironment. Since version 2.22, NSSM can rotate existing output files when redirecting I/O. +Since version 2.22, NSSM can set service display name, description and startup +type. + Usage ----- diff --git a/gui.cpp b/gui.cpp index bef4d4e..91c9e73 100644 --- a/gui.cpp +++ b/gui.cpp @@ -1,6 +1,6 @@ #include "nssm.h" -static enum { NSSM_TAB_APPLICATION, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS }; +static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS }; static HWND tablist[NSSM_NUM_TABS]; static int selected_tab; @@ -116,6 +116,25 @@ int install(HWND window) { } } + /* Get details. */ + if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME), WM_GETTEXTLENGTH, 0, 0)) { + if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname, _countof(service->displayname))) { + popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DISPLAYNAME); + return 5; + } + } + + if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION), WM_GETTEXTLENGTH, 0, 0)) { + if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description, _countof(service->description))) { + popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DESCRIPTION); + return 5; + } + } + + HWND combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP); + service->startup = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0); + if (service->startup == CB_ERR) service->startup = 0; + /* Get stop method stuff. */ check_stop_method(service, NSSM_STOP_METHOD_CONSOLE, IDC_METHOD_CONSOLE); check_stop_method(service, NSSM_STOP_METHOD_WINDOW, IDC_METHOD_WINDOW); @@ -127,7 +146,7 @@ int install(HWND window) { /* Get exit action stuff. */ check_method_timeout(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay); - HWND combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT); + combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT); service->default_exit_action = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0); if (service->default_exit_action == CB_ERR) service->default_exit_action = 0; @@ -471,6 +490,21 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) { tablist[NSSM_TAB_APPLICATION] = CreateDialog(0, MAKEINTRESOURCE(IDD_APPLICATION), window, tab_dlg); ShowWindow(tablist[NSSM_TAB_APPLICATION], SW_SHOW); + /* Details tab. */ + tab.pszText = message_string(NSSM_GUI_TAB_DETAILS); + tab.cchTextMax = (int) _tcslen(tab.pszText); + SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_DETAILS, (LPARAM) &tab); + tablist[NSSM_TAB_DETAILS] = CreateDialog(0, MAKEINTRESOURCE(IDD_DETAILS), window, tab_dlg); + ShowWindow(tablist[NSSM_TAB_DETAILS], SW_HIDE); + + /* Set defaults. */ + combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP); + SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_AUTOMATIC, (LPARAM) message_string(NSSM_GUI_STARTUP_AUTOMATIC)); + SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DELAYED, (LPARAM) message_string(NSSM_GUI_STARTUP_DELAYED)); + SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_MANUAL, (LPARAM) message_string(NSSM_GUI_STARTUP_MANUAL)); + SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DISABLED, (LPARAM) message_string(NSSM_GUI_STARTUP_DISABLED)); + SendMessage(combo, CB_SETCURSEL, NSSM_STARTUP_AUTOMATIC, 0); + /* Shutdown tab. */ tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN); tab.cchTextMax = (int) _tcslen(tab.pszText); diff --git a/messages.mc b/messages.mc index 62fb9cd..427905e 100644 --- a/messages.mc +++ b/messages.mc @@ -297,6 +297,32 @@ Nessuna opzione valida specificata! . MessageId = +1 +SymbolicName = NSSM_GUI_INVALID_DISPLAYNAME +Severity = Informational +Language = English +Invalid displayname! +. +Language = French +Invalid displayname! +. +Language = Italian +Invalid displayname! +. + +MessageId = +1 +SymbolicName = NSSM_GUI_INVALID_DESCRIPTION +Severity = Informational +Language = English +Invalid description! +. +Language = French +Invalid description! +. +Language = Italian +Invalid description! +. + +MessageId = +1 SymbolicName = NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH Severity = Informational Language = English @@ -472,6 +498,19 @@ Applicazione%0 . MessageId = +1 +SymbolicName = NSSM_GUI_TAB_DETAILS +Severity = Informational +Language = English +Details%0 +. +Language = French +Details%0 +. +Language = Italian +Details%0 +. + +MessageId = +1 SymbolicName = NSSM_GUI_TAB_SHUTDOWN Severity = Informational Language = English @@ -537,6 +576,58 @@ Ambiente%0 . MessageId = +1 +SymbolicName = NSSM_GUI_STARTUP_AUTOMATIC +Severity = Informational +Language = English +Automatic%0 +. +Language = French +Automatic%0 +. +Language = Italian +Automatic%0 +. + +MessageId = +1 +SymbolicName = NSSM_GUI_STARTUP_DELAYED +Severity = Informational +Language = English +Automatic (Delayed Start)%0 +. +Language = French +Automatic (Delayed Start)%0 +. +Language = Italian +Automatic (Delayed Start)%0 +. + +MessageId = +1 +SymbolicName = NSSM_GUI_STARTUP_MANUAL +Severity = Informational +Language = English +Manual%0 +. +Language = French +Manual%0 +. +Language = Italian +Manual%0 +. + +MessageId = +1 +SymbolicName = NSSM_GUI_STARTUP_DISABLED +Severity = Informational +Language = English +Disabled%0 +. +Language = French +Disabled%0 +. +Language = Italian +Disabled%0 +. + +MessageId = +1 SymbolicName = NSSM_GUI_EXIT_RESTART Severity = Informational Language = English @@ -1239,7 +1330,7 @@ Il servizio %1 ha ricevuto un messaggio di controllo di servizio sconosciuto %2, . MessageId = +1 -SymbolicName = NSSM_EVENT_CHANGESERVICECONFIG2_FAILED +SymbolicName = NSSM_EVENT_SERVICE_CONFIG_FAILURE_ACTIONS_FAILED Severity = Informational Language = English Error configuring service failure actions for service %1. The service will not be subject to recovery actions if it exits gracefully with a non-zero exit code. @@ -1578,3 +1669,41 @@ Failed to rotate output file %2 for service %1. %3 failed for file %4: %5 . + +MessageId = +1 +SymbolicName = NSSM_EVENT_SERVICE_CONFIG_DESCRIPTION_FAILED +Severity = Informational +Language = English +Error setting description for service %1. +ChangeServiceConfig2() failed: +%2 +. +Language = French +Error setting description for service %1. +ChangeServiceConfig2() failed: +%2 +. +Language = Italian +Error setting description for service %1. +ChangeServiceConfig2() failed: +%2 +. + +MessageId = +1 +SymbolicName = NSSM_EVENT_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED +Severity = Informational +Language = English +Error configuring delayed startup for service %1. The service will start automatically. +ChangeServiceConfig2() failed: +%2 +. +Language = French +Error configuring delayed startup for service %1. The service will start automatically. +ChangeServiceConfig2() failed: +%2 +. +Language = Italian +Error configuring delayed startup for service %1. The service will start automatically. +ChangeServiceConfig2() failed: +%2 +. diff --git a/nssm.h b/nssm.h index 9d5d1d4..bdefdbe 100644 --- a/nssm.h +++ b/nssm.h @@ -55,6 +55,12 @@ void strip_basename(TCHAR *); #define NSSM_STOP_METHOD_THREADS (1 << 2) #define NSSM_STOP_METHOD_TERMINATE (1 << 3) +/* Startup types. */ +#define NSSM_STARTUP_AUTOMATIC 0 +#define NSSM_STARTUP_DELAYED 1 +#define NSSM_STARTUP_MANUAL 2 +#define NSSM_STARTUP_DISABLED 3 + /* Exit actions. */ #define NSSM_EXIT_RESTART 0 #define NSSM_EXIT_IGNORE 1 diff --git a/nssm.rc b/nssm.rc index 3b8667a..749b2f4 100644 --- a/nssm.rc +++ b/nssm.rc @@ -105,6 +105,20 @@ FONT 8, "MS Sans Serif" LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDD_DETAILS DIALOG 9, 20, 261, 75 +STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL +FONT 8, "MS Sans Serif" +{ + GROUPBOX "Details", IDC_STATIC, 7, 7, 251, 68 + LTEXT "Display name:", IDC_STATIC, 13, 18, 45, 8, SS_LEFT + EDITTEXT IDC_DISPLAYNAME, 70, 16, 184, 12, ES_AUTOHSCROLL + LTEXT "Description:", IDC_STATIC, 13, 34, 38, 8, SS_LEFT + EDITTEXT IDC_DESCRIPTION, 70, 32, 184, 22, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES + LTEXT "Startup type:", IDC_STATIC, 13, 60, 41, 8, SS_LEFT + COMBOBOX IDC_STARTUP, 70, 58, 100, 120, CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP +} + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_SHUTDOWN DIALOG 9, 20, 261, 75 STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL FONT 8, "MS Sans Serif" diff --git a/resource.h b/resource.h index ec82a78..26ef0e5 100644 --- a/resource.h +++ b/resource.h @@ -7,11 +7,12 @@ #define IDD_INSTALL 102 #define IDD_REMOVE 103 #define IDD_APPLICATION 104 -#define IDD_IO 105 -#define IDD_ROTATION 106 -#define IDD_APPEXIT 107 -#define IDD_SHUTDOWN 108 -#define IDD_ENVIRONMENT 109 +#define IDD_DETAILS 105 +#define IDD_IO 106 +#define IDD_ROTATION 107 +#define IDD_APPEXIT 108 +#define IDD_SHUTDOWN 109 +#define IDD_ENVIRONMENT 110 #define IDC_PATH 1000 #define IDC_TAB1 1001 #define IDC_CANCEL 1002 @@ -44,14 +45,17 @@ #define IDC_ROTATE_SECONDS 1030 #define IDC_ROTATE_BYTES_LOW_ENABLED 1031 #define IDC_ROTATE_BYTES_LOW 1032 +#define IDC_DISPLAYNAME 1033 +#define IDC_DESCRIPTION 1034 +#define IDC_STARTUP 1035 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_RESOURCE_VALUE 111 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1033 +#define _APS_NEXT_CONTROL_VALUE 1036 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/service.cpp b/service.cpp index 94cca76..5b75a41 100644 --- a/service.cpp +++ b/service.cpp @@ -145,14 +145,48 @@ int install_service(nssm_service_t *service) { TCHAR command[MAX_PATH]; GetModuleFileName(0, command, _countof(command)); + /* Startup type. */ + unsigned long startup; + switch (service->startup) { + case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break; + case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break; + default: startup = SERVICE_AUTO_START; + } + + /* Display name. */ + if (! service->displayname[0]) _sntprintf_s(service->displayname, _countof(service->displayname), _TRUNCATE, _T("%s"), service->name); + /* Create the service */ - service->handle = CreateService(services, service->name, service->name, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, command, 0, 0, 0, 0, 0); + service->handle = CreateService(services, service->name, service->displayname, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, startup, SERVICE_ERROR_NORMAL, command, 0, 0, 0, 0, 0); if (! service->handle) { print_message(stderr, NSSM_MESSAGE_CREATESERVICE_FAILED); CloseServiceHandle(services); return 5; } + if (service->description[0]) { + SERVICE_DESCRIPTION description; + ZeroMemory(&description, sizeof(description)); + description.lpDescription = service->description; + if (! ChangeServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, &description)) { + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DESCRIPTION_FAILED, service->name, error_string(GetLastError()), 0); + } + } + + if (service->startup == NSSM_STARTUP_DELAYED) { + SERVICE_DELAYED_AUTO_START_INFO delayed; + ZeroMemory(&delayed, sizeof(delayed)); + delayed.fDelayedAutostart = 1; + /* Delayed startup isn't supported until Vista. */ + if (! ChangeServiceConfig2(service->handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) { + unsigned long error = GetLastError(); + /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */ + if (error != ERROR_INVALID_LEVEL) { + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service->name, error_string(error), 0); + } + } + } + /* Now we need to put the parameters into the registry */ if (create_parameters(service)) { print_message(stderr, NSSM_MESSAGE_CREATE_PARAMETERS_FAILED); @@ -282,7 +316,7 @@ void set_service_recovery(nssm_service_t *service) { unsigned long error = GetLastError(); /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */ if (error != ERROR_INVALID_LEVEL) { - log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CHANGESERVICECONFIG2_FAILED, service->name, error_string(error), 0); + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_FAILURE_ACTIONS_FAILED, service->name, error_string(error), 0); } } } diff --git a/service.h b/service.h index 04327c3..474f365 100644 --- a/service.h +++ b/service.h @@ -13,11 +13,15 @@ #define KEY_LENGTH 255 #define VALUE_LENGTH 16383 #define SERVICE_NAME_LENGTH KEY_LENGTH - 55 +#define SERVICE_DISPLAYNAME_LENGTH 256 #define ACTION_LEN 16 typedef struct { TCHAR name[SERVICE_NAME_LENGTH]; + TCHAR displayname[SERVICE_DISPLAYNAME_LENGTH]; + TCHAR description[VALUE_LENGTH]; + unsigned long startup; TCHAR exe[EXE_LENGTH]; TCHAR flags[VALUE_LENGTH]; TCHAR dir[MAX_PATH]; -- 2.7.4