瀏覽代碼

Set environment from the GUI at install time.

Added an extra Environment tab to set a newline-separated list of
environment variables to replace or be added to the service environment.

Input is validated by relaunching nssm itself with the proposed
environment set.
Iain Patterson 10 年之前
父節點
當前提交
277723e318
共有 6 個文件被更改,包括 139 次插入4 次删除
  1. 3 0
      ChangeLog.txt
  2. 83 2
      gui.cpp
  3. 26 0
      messages.mc
  4. 10 0
      nssm.rc
  5. 12 0
      registry.cpp
  6. 5 2
      resource.h

+ 3 - 0
ChangeLog.txt

@@ -1,5 +1,8 @@
 Changes since 2.18
 -----------------
+  * Support AppEnvironmentExtra to append to the environment
+    instead of replacing it.
+
   * The GUI is significantly less sucky.
 
 Changes since 2.17

+ 83 - 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_NUM_TABS };
+static enum { NSSM_TAB_APPLICATION, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };
 static HWND tablist[NSSM_NUM_TABS];
 static int selected_tab;
 
@@ -120,7 +120,7 @@ int install(HWND window) {
       if (! GetDlgItemText(window, IDC_FLAGS, service->flags, sizeof(service->flags))) {
         popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_OPTIONS);
         return 4;
-      }
+      }
     }
 
     /* Get stop method stuff. */
@@ -143,6 +143,80 @@ int install(HWND window) {
     check_io("stdin", service->stdin_path, sizeof(service->stdin_path), IDC_STDIN);
     check_io("stdout", service->stdout_path, sizeof(service->stdout_path), IDC_STDOUT);
     check_io("stderr", service->stderr_path, sizeof(service->stderr_path), IDC_STDERR);
+
+    /* Get environment. */
+    unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);
+    if (envlen) {
+      char *env = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, envlen + 2);
+      if (! env) {
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "environment", "install()");
+        cleanup_nssm_service(service);
+        return 5;
+      }
+
+      if (! GetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, env, envlen + 1)) {
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);
+        HeapFree(GetProcessHeap(), 0, env);
+        cleanup_nssm_service(service);
+        return 5;
+      }
+
+      /* Strip CR and replace LF with NULL. */
+      unsigned long newlen = 0;
+      unsigned long i, j;
+      for (i = 0; i < envlen; i++) if (env[i] != '\r') newlen++;
+      /* Must end with two NULLs. */
+      newlen++;
+
+      char *newenv = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen);
+      if (! newenv) {
+        HeapFree(GetProcessHeap(), 0, env);
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "environment", "install()");
+        cleanup_nssm_service(service);
+        return 5;
+      }
+
+      for (i = 0, j = 0; i < envlen; i++) {
+        if (env[i] == '\r') continue;
+        if (env[i] == '\n') newenv[j] = '\0';
+        else newenv[j] = env[i];
+        j++;
+      }
+
+      HeapFree(GetProcessHeap(), 0, env);
+      env = newenv;
+      envlen = newlen;
+
+      /* Test the environment is valid. */
+      char path[MAX_PATH];
+      GetModuleFileName(0, path, sizeof(path));
+      STARTUPINFO si;
+      ZeroMemory(&si, sizeof(si));
+      si.cb = sizeof(si);
+      PROCESS_INFORMATION pi;
+      ZeroMemory(&pi, sizeof(pi));
+
+      if (! CreateProcess(0, path, 0, 0, 0, CREATE_SUSPENDED, env, 0, &si, &pi)) {
+        unsigned long error = GetLastError();
+        if (error == ERROR_INVALID_PARAMETER) {
+          popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);
+          HeapFree(GetProcessHeap(), 0, env);
+          envlen = 0;
+        }
+        cleanup_nssm_service(service);
+        return 5;
+      }
+      TerminateProcess(pi.hProcess, 0);
+
+      if (SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_GETCHECK, 0, 0) & BST_CHECKED) {
+        service->env = env;
+        service->envlen = envlen;
+      }
+      else {
+        service->env_extra = env;
+        service->env_extralen = envlen;
+      }
+    }
   }
 
   /* See if it works. */
@@ -426,6 +500,13 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       tablist[NSSM_TAB_IO] = CreateDialog(0, MAKEINTRESOURCE(IDD_IO), window, tab_dlg);
       ShowWindow(tablist[NSSM_TAB_IO], SW_HIDE);
 
+      /* Environment tab. */
+      tab.pszText = message_string(NSSM_GUI_TAB_ENVIRONMENT);
+      tab.cchTextMax = (int) strlen(tab.pszText) + 1;
+      SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ENVIRONMENT, (LPARAM) &tab);
+      tablist[NSSM_TAB_ENVIRONMENT] = CreateDialog(0, MAKEINTRESOURCE(IDD_ENVIRONMENT), window, tab_dlg);
+      ShowWindow(tablist[NSSM_TAB_ENVIRONMENT], SW_HIDE);
+
       selected_tab = 0;
 
       return 1;

+ 26 - 0
messages.mc

@@ -301,6 +301,19 @@ Errore durante la costruzione di ImagePath!\nQesto errore 
 oppure il mondo sta per finire oppure è accaduto qualcosa di ugualmente grave!
 .
 
+MessageId = +1
+SymbolicName = NSSM_GUI_INVALID_ENVIRONMENT
+Severity = Informational
+Language = English
+Environment should comprise strings of the form KEY=VALUE.
+.
+Language = French
+L'environnement devrait comprendre des chaînes sous la forme KEY=VALUE.
+.
+Language = Italian
+L'ambiente dovrebbe comprendere stringhe nella forma CHIAVE=VALORE.
+.
+
 MessageId = +1
 SymbolicName = NSSM_GUI_INSTALL_SERVICE_FAILED
 Severity = Informational
@@ -485,6 +498,19 @@ Language = Italian
 I/O
 .
 
+MessageId = +1
+SymbolicName = NSSM_GUI_TAB_ENVIRONMENT
+Severity = Informational
+Language = English
+Environment
+.
+Language = French
+Environnement
+.
+Language = Italian
+Ambiente
+.
+
 MessageId = +1
 SymbolicName = NSSM_GUI_EXIT_RESTART
 Severity = Informational

+ 10 - 0
nssm.rc

@@ -156,6 +156,16 @@ FONT 8, "MS Sans Serif"
     DEFPUSHBUTTON   "...", IDC_BROWSE_STDERR, 239, 47, 15, 14
 }
 
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDD_ENVIRONMENT DIALOG 9, 20, 261, 75
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL
+FONT 8, "MS Sans Serif"
+{
+    GROUPBOX        "Environment variables", IDC_STATIC, 7, 7, 251, 68
+    EDITTEXT        IDC_ENVIRONMENT, 13, 18, 238, 36, ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN
+    AUTOCHECKBOX    "Replace default environment (srvany compatible)", IDC_ENVIRONMENT_REPLACE, 13, 60, 238, 8
+}
+
 
 /////////////////////////////////////////////////////////////////////////////
 //

+ 12 - 0
registry.cpp

@@ -72,6 +72,18 @@ int create_parameters(nssm_service_t *service) {
   if (service->stdout_path[0]) set_expand_string(key, NSSM_REG_STDOUT, service->stdout_path);
   if (service->stderr_path[0]) set_expand_string(key, NSSM_REG_STDERR, service->stderr_path);
 
+  /* Environment */
+  if (service->env) {
+    if (RegSetValueEx(key, NSSM_REG_ENV, 0, REG_MULTI_SZ, (const unsigned char *) service->env, (unsigned long) service->envlen) != ERROR_SUCCESS) {
+      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);
+    }
+  }
+  if (service->env_extra) {
+    if (RegSetValueEx(key, NSSM_REG_ENV_EXTRA, 0, REG_MULTI_SZ, (const unsigned char *) service->env_extra, (unsigned long) service->env_extralen) != ERROR_SUCCESS) {
+      log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV_EXTRA, error_string(GetLastError()), 0);
+    }
+  }
+
   /* Close registry. */
   RegCloseKey(key);
 

+ 5 - 2
resource.h

@@ -10,6 +10,7 @@
 #define IDD_IO            105
 #define IDD_APPEXIT            106
 #define IDD_SHUTDOWN            107
+#define IDD_ENVIRONMENT            108
 #define IDC_PATH                        1000
 #define IDC_TAB1                        1001
 #define IDC_CANCEL                      1002
@@ -34,14 +35,16 @@
 #define IDC_APPEXIT                     1022
 #define IDC_DIR                         1023
 #define IDC_BROWSE_DIR                  1024
+#define IDC_ENVIRONMENT                 1025
+#define IDC_ENVIRONMENT_REPLACE         1026
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        108
+#define _APS_NEXT_RESOURCE_VALUE        109
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1024
+#define _APS_NEXT_CONTROL_VALUE         1027
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif