Browse Source

Set service details in the GUI.

The GUI can now set the service display name, description and startup
type.
Iain Patterson 9 years ago
parent
commit
a02019297d
9 changed files with 243 additions and 12 deletions
  1. 3 0
      ChangeLog.txt
  2. 3 0
      README.txt
  3. 36 2
      gui.cpp
  4. 130 1
      messages.mc
  5. 6 0
      nssm.h
  6. 14 0
      nssm.rc
  7. 11 7
      resource.h
  8. 36 2
      service.cpp
  9. 4 0
      service.h

+ 3 - 0
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

+ 3 - 0
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
 -----

+ 36 - 2
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);

+ 130 - 1
messages.mc

@@ -296,6 +296,32 @@ Language = Italian
 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
@@ -471,6 +497,19 @@ Language = Italian
 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
@@ -536,6 +575,58 @@ Language = Italian
 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
@@ -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
+.

+ 6 - 0
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

+ 14 - 0
nssm.rc

@@ -104,6 +104,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

+ 11 - 7
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

+ 36 - 2
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);
     }
   }
 }

+ 4 - 0
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];