Allocate new console by default.
authorIain Patterson <me@iain.cx>
Sat, 25 Jan 2014 21:45:56 +0000 (21:45 +0000)
committerIain Patterson <me@iain.cx>
Sun, 26 Jan 2014 14:31:22 +0000 (14:31 +0000)
Since the whole purpose of NSSM is to be able to make services out of
applications which expect to have a standard desktop environment, let's
simply allocate a new console for each one rather than do so only when
we try to redirect I/O.

A funky ASCII art banner identifies the console as belonging to the
service.  NSSM itself will detach from the console as soon as possible,
so if the service runs a graphical application the console may never be
seen.

The console can be suppressed by setting the REG_DWORD value
AppNoConsole to 1.

Note that services running console applications on Windows 2000 may
fail if the console is disabled.

14 files changed:
ChangeLog.txt
README.txt
gui.cpp
io.cpp
nssm.cpp
nssm.h
nssm.rc
process.cpp
registry.cpp
registry.h
resource.h
service.cpp
service.h
settings.cpp

index ddfb5f7..26810d5 100644 (file)
-Changes since 2.21
-------------------
-  * Existing services can now be managed using the GUI
-    or on the command line.
-
-  * NSSM can now set the priority class and processor
-    affinity of the managed application.
-
-  * NSSM can now apply an unconditional delay before
-    restarting the application.
-
-  * NSSM can now optionally rotate existing files when
-    redirecting I/O.
-
-  * Unqualified path names are now relative to the
-    application startup directory when redirecting I/O.
-
-  * NSSM can now set the service display name, description,
-    startup type and log on details.
-
-Changes since 2.20
-------------------
-  * Services installed from the GUI no longer have incorrect
-    AppParameters set in the registry.
-
-Changes since 2.19
-------------------
-  * Services installed from the commandline without using the
-    GUI no longer have incorrect AppStopMethod* registry
-    entries set.
-
-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
-------------------
-  * Timeouts for each shutdown method can be configured in
-    the registry.
-
-  * The GUI is slightly less sucky.
-
-Changes since 2.16
-------------------
-  * NSSM can now redirect the service's I/O streams to any path
-    capable of being opened by CreateFile().
-
-  * Allow building on Visual Studio Express.
-
-  * Silently ignore INTERROGATE control.
-
-  * Try to send Control-C events to console applications when
-    shutting them down.
-
-Changes since 2.15
-------------------
-  * Fixed case where NSSM could kill unrelated processes when
-    shutting down.
-
-Changes since 2.14
-------------------
-  * NSSM is now translated into Italian.
-
-  * Fixed GUI not allowing paths longer than 256 characters.
-
-Changes since 2.13
-------------------
-  * Fixed default GUI language being French not English.
-
-Changes since 2.12
-------------------
-  * Fixed failure to run on Windows 2000.
-
-Changes since 2.11
-------------------
-  * NSSM is now translated into French.
-
-  * Really ensure systems recovery actions can happen.
-
-    The change supposedly introduced in v2.4 to allow service recovery
-    actions to be activated when the application exits gracefully with
-    a non-zero error code didn't actually work.
-
-Changes since 2.10
-------------------
-  * Support AppEnvironment for compatibility with srvany.
-
-Changes since 2.9
------------------
-  * Fixed failure to compile messages.mc in paths containing spaces.
-
-  * Fixed edge case with CreateProcess().
-
-    Correctly handle the case where the application executable is under
-    a path which contains space and an executable sharing the initial
-    part of that path (up to a space) exists.
-
-Changes since 2.8
------------------
-  * Fixed failure to run on Windows versions prior to Vista.
-
-Changes since 2.7
------------------
-  * Read Application, AppDirectory and AppParameters before each restart so
-    a change to any one doesn't require restarting NSSM itself.
-
-  * Fixed messages not being sent to the event log correctly in some
-    cases.
-
-  * Try to handle (strictly incorrect) quotes in AppDirectory.
-
-    Windows directories aren't allowed to contain quotes so CreateProcess()
-    will fail if the AppDirectory is quoted.  Note that it succeeds even if
-    Application itself is quoted as the application plus parameters are
-    interpreted as a command line.
-
-  * Fixed failed to write full arguments to AppParameters when
-    installing a service.
-
-  * Throttle restarts.
-
-    Back off from restarting the application immediately if it starts
-    successfully but exits too soon.  The default value of "too soon" is
-    1500 milliseconds.  This can be configured by adding a DWORD value
-    AppThrottle to the registry.
-    
-    Handle resume messages from the service console to restart the
-    application immediately even if it is throttled.
-
-  * Try to kill the process tree gracefully.
-
-    Before calling TerminateProcess() on all processes assocatiated with
-    the monitored application, enumerate all windows and threads and
-    post appropriate messages to them.  If the application bothers to
-    listen for such messages it has a chance to shut itself down gracefully.
-
-Changes since 2.6
------------------
-  * Handle missing registry values.
-
-    Warn if AppParameters is missing.  Warn if AppDirectory is missing or
-    unset and choose a fallback directory.
-    First try to find the parent directory of the application.  If that
-    fails, eg because the application path is just "notepad" or something,
-    start in the Windows directory.
-
-  * Kill process tree when stopping service.
-
-    Ensure that all child processes of the monitored application are
-    killed when the service stops by recursing through all running
-    processes and terminating those whose parent is the application
-    or one of its descendents.
-
-Changes since 2.5
------------------
-  * Removed incorrect ExpandEnvironmentStrings() error.
-
-    A log_event() call was inadvertently left in the code causing an error
-    to be set to the eventlog saying that ExpandEnvironmentStrings() had
-    failed when it had actually succeeded.
-
-Changes since 2.4
------------------
-  * Allow use of REG_EXPAND_SZ values in the registry.
-
-  * Don't suicide on exit status 0 by default.
-
-    Suiciding when the application exits 0 will cause recovery actions to be
-    taken.  Usually this is inappropriate.  Only suicide if there is an
-    explicit AppExit value for 0 in the registry.
-    
-    Technically such behaviour could be abused to do something like run a
-    script after successful completion of a service but in most cases a
-    suicide is undesirable when no actual failure occurred.
-
-  * Don't hang if startup parameters couldn't be determined.
-    Instead, signal that the service entered the STOPPED state.
-    Set START_PENDING state prior to actual startup.
-
-Changes since 2.3
------------------
-  * Ensure systems recovery actions can happen.
-
-    In Windows versions earlier than Vista the service manager would only
-    consider a service failed (and hence eligible for recovery action) if
-    the service exited without setting its state to SERVICE_STOPPED, even if
-    it signalled an error exit code.
-    In Vista and later the service manager can be configured to treat a
-    graceful shutdown with error code as a failure but this is not the
-    default behaviour.
-
-    Try to configure the service manager to use the new behaviour when
-    starting the service so users who set AppExit to Exit can use recovery
-    actions as expected.
-
-    Also recognise the new AppExit option Suicide for use on pre-Vista
-    systems.  When AppExit is Suicide don't stop the service but exit
-    inelegantly, which should be seen as a failure.
-
-Changes since 2.2
------------------
-  * Send properly formatted messages to the event log.
-
-  * Fixed truncation of very long path lengths in the registry.
-
-Changes since 2.1
------------------
- *  Decide how to handle application exit.
-
-    When the service exits with exit code n look in
-    HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppExit\<n>,
-    falling back to the unnamed value if no such code is listed.  Parse the
-    (string) value of this entry as follows:
-
-        Restart: Start the application again (NSSM default).
-        Ignore:  Do nothing (srvany default).
-        Exit:    Stop the service.
-
-Changes since 2.0
------------------
-  * Added support for building a 64-bit executable. 
-
-  * Added project files for newer versions of Visual Studio.
+Changes since 2.21\r
+------------------\r
+  * Existing services can now be managed using the GUI\r
+    or on the command line.\r
+\r
+  * NSSM can now set the priority class and processor\r
+    affinity of the managed application.\r
+\r
+  * NSSM can now apply an unconditional delay before\r
+    restarting the application.\r
+\r
+  * NSSM can now optionally rotate existing files when\r
+    redirecting I/O.\r
+\r
+  * Unqualified path names are now relative to the\r
+    application startup directory when redirecting I/O.\r
+\r
+  * NSSM can now set the service display name, description,\r
+    startup type and log on details.\r
+\r
+  * All services now receive a standard console window,\r
+    allowing them to read input correctly (if running in\r
+    interactive mode).\r
+\r
+Changes since 2.20\r
+------------------\r
+  * Services installed from the GUI no longer have incorrect\r
+    AppParameters set in the registry.\r
+\r
+Changes since 2.19\r
+------------------\r
+  * Services installed from the commandline without using the\r
+    GUI no longer have incorrect AppStopMethod* registry\r
+    entries set.\r
+\r
+Changes since 2.18\r
+------------------\r
+  * Support AppEnvironmentExtra to append to the environment\r
+    instead of replacing it.\r
+\r
+  * The GUI is significantly less sucky.\r
+\r
+Changes since 2.17\r
+------------------\r
+  * Timeouts for each shutdown method can be configured in\r
+    the registry.\r
+\r
+  * The GUI is slightly less sucky.\r
+\r
+Changes since 2.16\r
+------------------\r
+  * NSSM can now redirect the service's I/O streams to any path\r
+    capable of being opened by CreateFile().\r
+\r
+  * Allow building on Visual Studio Express.\r
+\r
+  * Silently ignore INTERROGATE control.\r
+\r
+  * Try to send Control-C events to console applications when\r
+    shutting them down.\r
+\r
+Changes since 2.15\r
+------------------\r
+  * Fixed case where NSSM could kill unrelated processes when\r
+    shutting down.\r
+\r
+Changes since 2.14\r
+------------------\r
+  * NSSM is now translated into Italian.\r
+\r
+  * Fixed GUI not allowing paths longer than 256 characters.\r
+\r
+Changes since 2.13\r
+------------------\r
+  * Fixed default GUI language being French not English.\r
+\r
+Changes since 2.12\r
+------------------\r
+  * Fixed failure to run on Windows 2000.\r
+\r
+Changes since 2.11\r
+------------------\r
+  * NSSM is now translated into French.\r
+\r
+  * Really ensure systems recovery actions can happen.\r
+\r
+    The change supposedly introduced in v2.4 to allow service recovery\r
+    actions to be activated when the application exits gracefully with\r
+    a non-zero error code didn't actually work.\r
+\r
+Changes since 2.10\r
+------------------\r
+  * Support AppEnvironment for compatibility with srvany.\r
+\r
+Changes since 2.9\r
+-----------------\r
+  * Fixed failure to compile messages.mc in paths containing spaces.\r
+\r
+  * Fixed edge case with CreateProcess().\r
+\r
+    Correctly handle the case where the application executable is under\r
+    a path which contains space and an executable sharing the initial\r
+    part of that path (up to a space) exists.\r
+\r
+Changes since 2.8\r
+-----------------\r
+  * Fixed failure to run on Windows versions prior to Vista.\r
+\r
+Changes since 2.7\r
+-----------------\r
+  * Read Application, AppDirectory and AppParameters before each restart so\r
+    a change to any one doesn't require restarting NSSM itself.\r
+\r
+  * Fixed messages not being sent to the event log correctly in some\r
+    cases.\r
+\r
+  * Try to handle (strictly incorrect) quotes in AppDirectory.\r
+\r
+    Windows directories aren't allowed to contain quotes so CreateProcess()\r
+    will fail if the AppDirectory is quoted.  Note that it succeeds even if\r
+    Application itself is quoted as the application plus parameters are\r
+    interpreted as a command line.\r
+\r
+  * Fixed failed to write full arguments to AppParameters when\r
+    installing a service.\r
+\r
+  * Throttle restarts.\r
+\r
+    Back off from restarting the application immediately if it starts\r
+    successfully but exits too soon.  The default value of "too soon" is\r
+    1500 milliseconds.  This can be configured by adding a DWORD value\r
+    AppThrottle to the registry.\r
+    \r
+    Handle resume messages from the service console to restart the\r
+    application immediately even if it is throttled.\r
+\r
+  * Try to kill the process tree gracefully.\r
+\r
+    Before calling TerminateProcess() on all processes assocatiated with\r
+    the monitored application, enumerate all windows and threads and\r
+    post appropriate messages to them.  If the application bothers to\r
+    listen for such messages it has a chance to shut itself down gracefully.\r
+\r
+Changes since 2.6\r
+-----------------\r
+  * Handle missing registry values.\r
+\r
+    Warn if AppParameters is missing.  Warn if AppDirectory is missing or\r
+    unset and choose a fallback directory.\r
+    First try to find the parent directory of the application.  If that\r
+    fails, eg because the application path is just "notepad" or something,\r
+    start in the Windows directory.\r
+\r
+  * Kill process tree when stopping service.\r
+\r
+    Ensure that all child processes of the monitored application are\r
+    killed when the service stops by recursing through all running\r
+    processes and terminating those whose parent is the application\r
+    or one of its descendents.\r
+\r
+Changes since 2.5\r
+-----------------\r
+  * Removed incorrect ExpandEnvironmentStrings() error.\r
+\r
+    A log_event() call was inadvertently left in the code causing an error\r
+    to be set to the eventlog saying that ExpandEnvironmentStrings() had\r
+    failed when it had actually succeeded.\r
+\r
+Changes since 2.4\r
+-----------------\r
+  * Allow use of REG_EXPAND_SZ values in the registry.\r
+\r
+  * Don't suicide on exit status 0 by default.\r
+\r
+    Suiciding when the application exits 0 will cause recovery actions to be\r
+    taken.  Usually this is inappropriate.  Only suicide if there is an\r
+    explicit AppExit value for 0 in the registry.\r
+    \r
+    Technically such behaviour could be abused to do something like run a\r
+    script after successful completion of a service but in most cases a\r
+    suicide is undesirable when no actual failure occurred.\r
+\r
+  * Don't hang if startup parameters couldn't be determined.\r
+    Instead, signal that the service entered the STOPPED state.\r
+    Set START_PENDING state prior to actual startup.\r
+\r
+Changes since 2.3\r
+-----------------\r
+  * Ensure systems recovery actions can happen.\r
+\r
+    In Windows versions earlier than Vista the service manager would only\r
+    consider a service failed (and hence eligible for recovery action) if\r
+    the service exited without setting its state to SERVICE_STOPPED, even if\r
+    it signalled an error exit code.\r
+    In Vista and later the service manager can be configured to treat a\r
+    graceful shutdown with error code as a failure but this is not the\r
+    default behaviour.\r
+\r
+    Try to configure the service manager to use the new behaviour when\r
+    starting the service so users who set AppExit to Exit can use recovery\r
+    actions as expected.\r
+\r
+    Also recognise the new AppExit option Suicide for use on pre-Vista\r
+    systems.  When AppExit is Suicide don't stop the service but exit\r
+    inelegantly, which should be seen as a failure.\r
+\r
+Changes since 2.2\r
+-----------------\r
+  * Send properly formatted messages to the event log.\r
+\r
+  * Fixed truncation of very long path lengths in the registry.\r
+\r
+Changes since 2.1\r
+-----------------\r
+ *  Decide how to handle application exit.\r
+\r
+    When the service exits with exit code n look in\r
+    HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppExit\<n>,\r
+    falling back to the unnamed value if no such code is listed.  Parse the\r
+    (string) value of this entry as follows:\r
+\r
+        Restart: Start the application again (NSSM default).\r
+        Ignore:  Do nothing (srvany default).\r
+        Exit:    Stop the service.\r
+\r
+Changes since 2.0\r
+-----------------\r
+  * Added support for building a 64-bit executable.\r
+\r
+  * Added project files for newer versions of Visual Studio.\r
index aa1fc9f..edddf04 100644 (file)
@@ -262,6 +262,17 @@ so the actual time to shutdown may be longer than the sum of all configured
 timeouts if the application spawns multiple subprocesses.\r
 \r
 \r
+Console window\r
+--------------\r
+By default, NSSM will create a console window so that applications which\r
+are capable of reading user input can do so - subject to the service being\r
+allowed to interact with the desktop.\r
+\r
+Creation of the console can be suppressed by setting the integer (REG_DWORD)\r
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppNoConsole\r
+registry value to 1.\r
+\r
+\r
 I/O redirection\r
 ---------------\r
 NSSM can redirect the managed application's I/O to any path capable of being\r
diff --git a/gui.cpp b/gui.cpp
index 694e0e2..dfa1a22 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -117,6 +117,10 @@ int nssm_gui(int resource, nssm_service_t *service) {
       }\r
     }\r
 \r
+    if (service->no_console) {
+      SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_CONSOLE, BM_SETCHECK, BST_UNCHECKED, 0);\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
@@ -478,6 +482,9 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
     }\r
   }\r
 \r
+  if (SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_CONSOLE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->no_console = 0;
+  else service->no_console = 1;
+
   /* 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
@@ -956,6 +963,8 @@ INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       SendMessage(combo, CB_INSERTSTRING, NSSM_IDLE_PRIORITY, (LPARAM) message_string(NSSM_GUI_IDLE_PRIORITY_CLASS));\r
       SendMessage(combo, CB_SETCURSEL, NSSM_NORMAL_PRIORITY, 0);\r
 \r
+      SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_CONSOLE, BM_SETCHECK, BST_CHECKED, 0);\r
+
       list = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY);\r
       n = num_cpus();\r
       SendMessage(list, LB_SETCOLUMNWIDTH, 16, 0);\r
diff --git a/io.cpp b/io.cpp
index 42e4447..41139a0 100644 (file)
--- a/io.cpp
+++ b/io.cpp
@@ -231,7 +231,26 @@ void rotate_file(TCHAR *service_name, TCHAR *path, unsigned long seconds, unsign
 }\r
 \r
 int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {\r
-  bool redirect = false;\r
+  /* Allocate a new console so we get a fresh stdin, stdout and stderr. */\r
+  if (si && ! service->no_console) {\r
+    FreeConsole();\r
+    AllocConsole();\r
+    banner();\r
+\r
+    /* Set a title like "[NSSM] Jenkins" */\r
+    TCHAR displayname[SERVICE_NAME_LENGTH];\r
+    unsigned long len = _countof(displayname);\r
+    SC_HANDLE services = open_service_manager();\r
+    if (services) {\r
+      if (! GetServiceDisplayName(services, service->name, displayname, &len)) ZeroMemory(displayname, sizeof(displayname));\r
+      CloseServiceHandle(services);\r
+    }\r
+    if (! displayname[0]) _sntprintf_s(displayname, _countof(displayname), _TRUNCATE, _T("%s"), service->name);\r
+\r
+    TCHAR title[65535];\r
+    _sntprintf_s(title, _countof(title), _TRUNCATE, _T("[%s] %s"), NSSM, displayname);\r
+    SetConsoleTitle(title);\r
+  }\r
 \r
   /* stdin */\r
   if (get_createfile_parameters(key, NSSM_REG_STDIN, service->stdin_path, &service->stdin_sharing, NSSM_STDIN_SHARING, &service->stdin_disposition, NSSM_STDIN_DISPOSITION, &service->stdin_flags, NSSM_STDIN_FLAGS)) {\r
@@ -245,8 +264,6 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
       log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEFILE_FAILED, service->stdin_path, error_string(GetLastError()), 0);\r
       return 2;\r
     }\r
-\r
-    redirect = true;\r
   }\r
 \r
   /* stdout */\r
@@ -277,8 +294,6 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
       }\r
       service->rotate_stdout_online = NSSM_ROTATE_OFFLINE;\r
     }\r
-\r
-    redirect = true;\r
   }\r
 \r
   /* stderr */\r
@@ -325,35 +340,18 @@ int get_output_handles(nssm_service_t *service, HKEY key, STARTUPINFO *si) {
         }\r
         service->rotate_stderr_online = NSSM_ROTATE_OFFLINE;\r
       }\r
-\r
-      redirect = true;\r
     }\r
   }\r
 \r
-  if (! redirect || ! si) return 0;\r
-\r
-  /* Allocate a new console so we get a fresh stdin, stdout and stderr. */\r
-  FreeConsole();\r
-  AllocConsole();\r
-\r
-  /* Set a title like "[NSSM] Jenkins" */\r
-  TCHAR displayname[SERVICE_NAME_LENGTH];\r
-  unsigned long len = _countof(displayname);\r
-  SC_HANDLE services = open_service_manager();\r
-  if (services) {\r
-    if (! GetServiceDisplayName(services, service->name, displayname, &len)) _sntprintf_s(displayname, _countof(displayname), _TRUNCATE, _T("%s"), service->name);\r
-    CloseServiceHandle(services);\r
-  }\r
-\r
-  TCHAR title[65535];\r
-  _sntprintf_s(title, _countof(title), _TRUNCATE, _T("[%s] %s\n"), NSSM, displayname);\r
-  SetConsoleTitle(title);\r
+  if (! si) return 0;\r
 \r
   /*\r
     We need to set the startup_info flags to make the new handles\r
     inheritable by the new process.\r
   */\r
-  if (si) si->dwFlags |= STARTF_USESTDHANDLES;\r
+  si->dwFlags |= STARTF_USESTDHANDLES;\r
+\r
+  if (service->no_console) return 0;\r
 \r
   /* Redirect other handles. */\r
   if (! si->hStdInput) {\r
index 931496a..8c36780 100644 (file)
--- a/nssm.cpp
+++ b/nssm.cpp
@@ -82,6 +82,135 @@ int num_cpus() {
   return (int) i;\r
 }\r
 \r
+static inline void block(unsigned int a, short x, short y, unsigned long n) {\r
+  HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);\r
+  TCHAR s = _T(' ');\r
+\r
+  unsigned long out;\r
+  COORD c = { x, y };\r
+  FillConsoleOutputAttribute(h, a, n, c, &out);\r
+  FillConsoleOutputCharacter(h, s, n, c, &out);\r
+}\r
+\r
+static inline void R(short x, short y, unsigned long n) {\r
+  block(BACKGROUND_RED | BACKGROUND_INTENSITY, x, y, n);\r
+}\r
+\r
+static inline void r(short x, short y, unsigned long n) {\r
+  block(BACKGROUND_RED, x, y, n);\r
+}\r
+\r
+static inline void b(short x, short y, unsigned long n) {\r
+  block(0, x, y, n);\r
+}\r
+\r
+void banner() {\r
+  short y = 0;\r
+\r
+  b(0, y, 80);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(18, y, 5); r(28, y, 4); r(41, y, 4); r(68, y, 1);\r
+  R(6, y, 5); R(19, y, 4); R(29, y, 1); R(32, y, 3); R(42, y, 1); R(45, y, 3); R(52, y, 5); R(69, y, 4);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(8, y, 4); r(20, y, 1); r(28, y, 1); r(33, y, 3); r(41, y, 1); r(46, y, 3); r (57, y, 1);\r
+  R(9, y, 2); R(21, y, 1); R(27, y, 1); R(34, y, 1); R(40, y, 1); R(47, y, 1); R(54, y, 3); R(68, y, 3);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(12, y, 1); r(20, y, 1); r(26, y, 1); r(34, y, 2); r(39, y, 1); r(47, y, 2); r(67, y, 2);\r
+  R(9, y, 3); R(21, y, 1); R(27, y, 1); R(40, y, 1); R(54, y, 1); R(56, y, 2); R(67, y, 1); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(20, y, 1); r(26, y, 1); r (35, y, 1); r(39, y, 1); r(48, y, 1); r(58, y, 1);\r
+  R(10, y, 3); R(21, y, 1); R(27, y, 1); R(40, y, 1); R(54, y, 1); R(56, y, 2); R(67, y, 1); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(56, y, 1); r(66, y, 2);\r
+  R(11, y, 3); R(21, y, 1); R(26, y, 2); R(39, y, 2); R(54, y, 1); R(57, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(26, y, 1); r(39, y, 1); r(59, y, 1);\r
+  R(12, y, 3); R(21, y, 1); R(27, y, 2); R(40, y, 2); R(54, y, 1); R(57, y, 2); R(66, y, 1); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(12, y, 4); r(30, y, 1); r(43, y, 1); r(57, y, 1); r(65, y, 2);\r
+  R(13, y, 2); R(21, y, 1); R(27, y, 3); R(40, y, 3); R(54, y, 1); R(58, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(13, y, 4); r(27, y, 7); r(40, y, 7);\r
+  R(14, y, 2); R(21, y, 1); R(28, y, 5); R(41, y, 5); R(54, y, 1); R(58, y, 2); R(65, y, 1); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(60, y, 1); r(65, y, 1);\r
+  R(14, y, 3); R(21, y, 1); R(29, y, 6); R(42, y, 6); R(54, y, 1); R(58, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(31, y, 1); r(44, y, 1); r(58, y, 1); r(64, y, 1);\r
+  R(15, y, 3); R(21, y, 1); R(32, y, 4); R(45, y, 4); R(54, y, 1); R(59, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(33, y, 1); r(46, y, 1); r(61, y, 1); r(64, y, 1);\r
+  R(16, y, 3); R(21, y, 1); R(34, y, 2); R(47, y, 2); R(54, y, 1); R(59, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(16, y, 4); r(36, y, 1); r(49, y, 1); r(59, y, 1); r(63, y, 1);\r
+  R(17, y, 2); R(21, y, 1); R(34, y, 2); R(47, y, 2); R(54, y, 1); R(60, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(9, y, 1); r(17, y, 4); r(26, y, 1); r(36, y, 1); r(39, y, 1); r(49, y, 1);\r
+  R(18, y, 2); R(21, y, 1); R(35, y, 1); R(48, y, 1); R(54, y, 1); R(60, y, 2); R(63, y, 1); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(26, y, 2); r(39, y, 2); r(63, y, 1);\r
+  R(9, y, 1); R(18, y, 4); R(35, y, 1); R(48, y, 1); R(54, y, 1); R(60, y, 3); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(34, y, 1); r(47, y, 1); r(60, y, 1);\r
+  R(9, y, 1); R(19, y, 3); R(26, y, 2); R(35, y, 1); R(39, y, 2); R(48, y, 1); R(54, y, 1); R(61, y, 2); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(8, y, 1); r(35, y, 1); r(48, y, 1); r(62, y, 1); r(71, y, 1);\r
+  R(9, y, 1); R(20, y, 2); R(26, y, 3); R(34, y, 1); R(39, y, 3); R(47, y, 1); R(54, y, 1); R(61, y, 1); R(69, y, 2);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  r(11, y, 1); r(26, y, 1); r(28, y, 5); r(39, y, 1); r(41, y, 5); r(51, y, 7); r(61, y, 1); r(66, y, 8);\r
+  R(7, y, 4); R(21, y, 1); R(29, y, 1); R(33, y, 1); R(42, y, 1); R(46, y, 1); R(52, y, 5); R(67, y, 7);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  y++;\r
+\r
+  b(0, y, 80);\r
+  y++;\r
+}\r
+\r
 int _tmain(int argc, TCHAR **argv) {\r
   check_console();\r
 \r
diff --git a/nssm.h b/nssm.h
index 6d1f315..cbfa15f 100644 (file)
--- a/nssm.h
+++ b/nssm.h
@@ -57,6 +57,7 @@ int str_number(const TCHAR *, unsigned long *, TCHAR **);
 int str_number(const TCHAR *, unsigned long *);\r
 int num_cpus();\r
 int usage(int);\r
+void banner();\r
 \r
 #define NSSM _T("NSSM")\r
 #ifdef _WIN64\r
diff --git a/nssm.rc b/nssm.rc
index e6c5871..e2193a1 100644 (file)
Binary files a/nssm.rc and b/nssm.rc differ
index 0a8c18b..1cc6a73 100644 (file)
@@ -208,8 +208,6 @@ int kill_console(nssm_service_t *service) {
         return 2;
 
       case ERROR_ACCESS_DENIED:
-        /* Maybe we already allocated a console for output. */
-        if (service->stdin_path[0] || service->stdout_path[0] || service->stderr_path[0]) break;
       default:
         /* We already have a console. */
         log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_ATTACHCONSOLE_FAILED, service->name, error_string(ret), 0);
index bd79dc3..3410e4a 100644 (file)
@@ -119,6 +119,8 @@ int create_parameters(nssm_service_t *service, bool editing) {
   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
+  if (service->no_console) set_number(key, NSSM_REG_NO_CONSOLE, 1);\r
+  else if (editing) RegDeleteValue(key, NSSM_REG_NO_CONSOLE);\r
 \r
   /* Environment */\r
   if (service->env) {\r
@@ -489,6 +491,9 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
   if (get_number(key, NSSM_REG_ROTATE_BYTES_LOW, &service->rotate_bytes_low, false) != 1) service->rotate_bytes_low = 0;\r
   if (get_number(key, NSSM_REG_ROTATE_BYTES_HIGH, &service->rotate_bytes_high, false) != 1) service->rotate_bytes_high = 0;\r
 \r
+  /* Try to get force new console setting - may fail. */\r
+  if (get_number(key, NSSM_REG_NO_CONSOLE, &service->no_console, false) != 1) service->no_console = 0;\r
+\r
   /* Change to startup directory in case stdout/stderr are relative paths. */\r
   TCHAR cwd[PATH_LENGTH];\r
   GetCurrentDirectory(_countof(cwd), cwd);\r
index aa14e00..1734d4e 100644 (file)
@@ -27,6 +27,7 @@
 #define NSSM_REG_ROTATE_BYTES_HIGH _T("AppRotateBytesHigh")\r
 #define NSSM_REG_PRIORITY _T("AppPriority")\r
 #define NSSM_REG_AFFINITY _T("AppAffinity")\r
+#define NSSM_REG_NO_CONSOLE _T("AppNoConsole")\r
 #define NSSM_STDIO_LENGTH 29\r
 \r
 HKEY open_registry(const TCHAR *, const TCHAR *, REGSAM sam);\r
index 0fa1f5c..0ddd90d 100644 (file)
@@ -61,6 +61,7 @@
 #define IDC_PRIORITY                    1042\r
 #define IDC_AFFINITY_ALL                1043\r
 #define IDC_AFFINITY                    1044\r
+#define IDC_CONSOLE                     1045\r
 \r
 // Next default values for new objects\r
 // \r
@@ -68,7 +69,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
 #define _APS_NEXT_RESOURCE_VALUE        115\r
 #define _APS_NEXT_COMMAND_VALUE         40001\r
-#define _APS_NEXT_CONTROL_VALUE         1045\r
+#define _APS_NEXT_CONTROL_VALUE         1046\r
 #define _APS_NEXT_SYMED_VALUE           101\r
 #endif\r
 #endif\r
index 284b5ec..e8a1569 100644 (file)
@@ -1697,6 +1697,8 @@ void CALLBACK end_service(void *arg, unsigned char why) {
   if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid);\r
   service->pid = 0;\r
 \r
+  if (! service->no_console) FreeConsole();\r
+\r
   /*\r
     The why argument is true if our wait timed out or false otherwise.\r
     Our wait is infinite so why will never be true when called by the system.\r
index 4eed6ad..496b54a 100644 (file)
--- a/service.h
+++ b/service.h
@@ -53,6 +53,7 @@ typedef struct {
   TCHAR *env_extra;\r
   unsigned long env_extralen;\r
   unsigned long priority;\r
+  unsigned long no_console;\r
   TCHAR stdin_path[PATH_LENGTH];\r
   unsigned long stdin_sharing;\r
   unsigned long stdin_disposition;\r
index a3d301b..73b8d0d 100644 (file)
@@ -810,6 +810,7 @@ settings_t settings[] = {
   { NSSM_REG_AFFINITY, REG_SZ, 0, false, 0, setting_set_affinity, setting_get_affinity },
   { NSSM_REG_ENV, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
   { NSSM_REG_ENV_EXTRA, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
+  { NSSM_REG_NO_CONSOLE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_PRIORITY, REG_SZ, (void *) priority_strings[NSSM_NORMAL_PRIORITY], false, 0, setting_set_priority, setting_get_priority },
   { NSSM_REG_RESTART_DELAY, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_STDIN, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },