Set service details in the GUI.
authorIain Patterson <me@iain.cx>
Sat, 21 Dec 2013 16:10:33 +0000 (16:10 +0000)
committerIain Patterson <me@iain.cx>
Sat, 21 Dec 2013 16:10:33 +0000 (16:10 +0000)
The GUI can now set the service display name, description and startup
type.

ChangeLog.txt
README.txt
gui.cpp
messages.mc
nssm.h
nssm.rc
resource.h
service.cpp
service.h

index e73a9aa..8bd2dd0 100644 (file)
@@ -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
index 366e6f3..8be1383 100644 (file)
@@ -55,6 +55,9 @@ AppEnvironment.
 \r
 Since version 2.22, NSSM can rotate existing output files when redirecting I/O.\r
 \r
+Since version 2.22, NSSM can set service display name, description and startup\r
+type.\r
+\r
 \r
 Usage\r
 -----\r
diff --git a/gui.cpp b/gui.cpp
index bef4d4e..91c9e73 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -1,6 +1,6 @@
 #include "nssm.h"\r
 \r
-static enum { NSSM_TAB_APPLICATION, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
+static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
 static HWND tablist[NSSM_NUM_TABS];\r
 static int selected_tab;\r
 \r
@@ -116,6 +116,25 @@ int install(HWND window) {
       }\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
+    }\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
+\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
@@ -127,7 +146,7 @@ int install(HWND window) {
 \r
     /* Get exit action stuff. */\r
     check_method_timeout(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
-    HWND combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\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
@@ -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);\r
       ShowWindow(tablist[NSSM_TAB_APPLICATION], SW_SHOW);\r
 \r
+      /* Details tab. */\r
+      tab.pszText = message_string(NSSM_GUI_TAB_DETAILS);\r
+      tab.cchTextMax = (int) _tcslen(tab.pszText);\r
+      SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_DETAILS, (LPARAM) &tab);\r
+      tablist[NSSM_TAB_DETAILS] = CreateDialog(0, MAKEINTRESOURCE(IDD_DETAILS), window, tab_dlg);\r
+      ShowWindow(tablist[NSSM_TAB_DETAILS], SW_HIDE);\r
+\r
+      /* Set defaults. */\r
+      combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
+      SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_AUTOMATIC, (LPARAM) message_string(NSSM_GUI_STARTUP_AUTOMATIC));\r
+      SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DELAYED, (LPARAM) message_string(NSSM_GUI_STARTUP_DELAYED));\r
+      SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_MANUAL, (LPARAM) message_string(NSSM_GUI_STARTUP_MANUAL));\r
+      SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DISABLED, (LPARAM) message_string(NSSM_GUI_STARTUP_DISABLED));\r
+      SendMessage(combo, CB_SETCURSEL, NSSM_STARTUP_AUTOMATIC, 0);\r
+\r
       /* Shutdown tab. */\r
       tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN);\r
       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
index 62fb9cd..427905e 100644 (file)
@@ -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
+.
diff --git a/nssm.h b/nssm.h
index 9d5d1d4..bdefdbe 100644 (file)
--- a/nssm.h
+++ b/nssm.h
@@ -55,6 +55,12 @@ void strip_basename(TCHAR *);
 #define NSSM_STOP_METHOD_THREADS (1 << 2)\r
 #define NSSM_STOP_METHOD_TERMINATE (1 << 3)\r
 \r
+/* Startup types. */\r
+#define NSSM_STARTUP_AUTOMATIC 0\r
+#define NSSM_STARTUP_DELAYED 1\r
+#define NSSM_STARTUP_MANUAL 2\r
+#define NSSM_STARTUP_DISABLED 3\r
+\r
 /* Exit actions. */\r
 #define NSSM_EXIT_RESTART 0\r
 #define NSSM_EXIT_IGNORE 1\r
diff --git a/nssm.rc b/nssm.rc
index 3b8667a..749b2f4 100644 (file)
--- a/nssm.rc
+++ b/nssm.rc
@@ -104,6 +104,20 @@ FONT 8, "MS Sans Serif"
 \r
 \r
 \r
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
+IDD_DETAILS DIALOG 9, 20, 261, 75\r
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
+FONT 8, "MS Sans Serif"\r
+{\r
+    GROUPBOX        "Details", IDC_STATIC, 7, 7, 251, 68\r
+    LTEXT           "Display name:", IDC_STATIC, 13, 18, 45, 8, SS_LEFT\r
+    EDITTEXT        IDC_DISPLAYNAME, 70, 16, 184, 12, ES_AUTOHSCROLL\r
+    LTEXT           "Description:", IDC_STATIC, 13, 34, 38, 8, SS_LEFT\r
+    EDITTEXT        IDC_DESCRIPTION, 70, 32, 184, 22, ES_AUTOHSCROLL, WS_EX_ACCEPTFILES\r
+    LTEXT           "Startup type:", IDC_STATIC, 13, 60, 41, 8, SS_LEFT\r
+    COMBOBOX        IDC_STARTUP, 70, 58, 100, 120, CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP\r
+}\r
+\r
 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
 IDD_SHUTDOWN DIALOG 9, 20, 261, 75\r
 STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
index ec82a78..26ef0e5 100644 (file)
@@ -7,11 +7,12 @@
 #define IDD_INSTALL                   102\r
 #define IDD_REMOVE            103\r
 #define IDD_APPLICATION            104\r
-#define IDD_IO            105\r
-#define IDD_ROTATION        106\r
-#define IDD_APPEXIT            107\r
-#define IDD_SHUTDOWN            108\r
-#define IDD_ENVIRONMENT            109\r
+#define IDD_DETAILS            105\r
+#define IDD_IO            106\r
+#define IDD_ROTATION        107\r
+#define IDD_APPEXIT            108\r
+#define IDD_SHUTDOWN            109\r
+#define IDD_ENVIRONMENT            110\r
 #define IDC_PATH                        1000\r
 #define IDC_TAB1                        1001\r
 #define IDC_CANCEL                      1002\r
 #define IDC_ROTATE_SECONDS              1030\r
 #define IDC_ROTATE_BYTES_LOW_ENABLED    1031\r
 #define IDC_ROTATE_BYTES_LOW            1032\r
+#define IDC_DISPLAYNAME                 1033\r
+#define IDC_DESCRIPTION                 1034\r
+#define IDC_STARTUP                     1035\r
 \r
 // Next default values for new objects\r
 // \r
 #ifdef APSTUDIO_INVOKED\r
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
-#define _APS_NEXT_RESOURCE_VALUE        110\r
+#define _APS_NEXT_RESOURCE_VALUE        111\r
 #define _APS_NEXT_COMMAND_VALUE         40001\r
-#define _APS_NEXT_CONTROL_VALUE         1033\r
+#define _APS_NEXT_CONTROL_VALUE         1036\r
 #define _APS_NEXT_SYMED_VALUE           101\r
 #endif\r
 #endif\r
index 94cca76..5b75a41 100644 (file)
@@ -145,14 +145,48 @@ int install_service(nssm_service_t *service) {
   TCHAR command[MAX_PATH];\r
   GetModuleFileName(0, command, _countof(command));\r
 \r
+  /* Startup type. */\r
+  unsigned long startup;\r
+  switch (service->startup) {\r
+    case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break;\r
+    case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break;\r
+    default: startup = SERVICE_AUTO_START;\r
+  }\r
+\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->name, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, command, 0, 0, 0, 0, 0);\r
+  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);\r
   if (! service->handle) {\r
     print_message(stderr, NSSM_MESSAGE_CREATESERVICE_FAILED);\r
     CloseServiceHandle(services);\r
     return 5;\r
   }\r
 \r
+  if (service->description[0]) {\r
+    SERVICE_DESCRIPTION description;\r
+    ZeroMemory(&description, sizeof(description));\r
+    description.lpDescription = service->description;\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
+    }\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
@@ -282,7 +316,7 @@ void set_service_recovery(nssm_service_t *service) {
     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_CHANGESERVICECONFIG2_FAILED, service->name, error_string(error), 0);\r
+      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_FAILURE_ACTIONS_FAILED, service->name, error_string(error), 0);\r
     }\r
   }\r
 }\r
index 04327c3..474f365 100644 (file)
--- a/service.h
+++ b/service.h
 #define KEY_LENGTH 255\r
 #define VALUE_LENGTH 16383\r
 #define SERVICE_NAME_LENGTH KEY_LENGTH - 55\r
+#define SERVICE_DISPLAYNAME_LENGTH 256\r
 \r
 #define ACTION_LEN 16\r
 \r
 typedef struct {\r
   TCHAR name[SERVICE_NAME_LENGTH];\r
+  TCHAR displayname[SERVICE_DISPLAYNAME_LENGTH];\r
+  TCHAR description[VALUE_LENGTH];\r
+  unsigned long startup;\r
   TCHAR exe[EXE_LENGTH];\r
   TCHAR flags[VALUE_LENGTH];\r
   TCHAR dir[MAX_PATH];\r