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.
simulating a Control-C keypress. If they have installed a handler routine\r
they can clean up and shut down gracefully on receipt of the event.\r
\r
+Since version 2.17, NSSM can redirect the managed application's I/O streams\r
+to an arbitrary path.\r
+\r
+\r
Usage\r
-----\r
In the usage notes below, arguments to the program may be written in angle \r
If only the default action is set to Suicide NSSM will instead exit gracefully.\r
\r
\r
+I/O redirection\r
+---------------\r
+NSSM can redirect the managed application's I/O to any path capable of being\r
+opened by CreateFile(). This enables, for example, capturing the log output\r
+of an application which would otherwise only write to the console or accepting\r
+input from a serial port.\r
+\r
+NSSM will look in the registry under\r
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters for the keys\r
+corresponding to arguments to CreateFile(). All are optional. If no path is\r
+given for a particular stream it will not be redirected. If a path is given\r
+but any of the other values are omitted they will be receive sensible defaults.\r
+\r
+ AppStdin: Path to receive input.\r
+ AppStdout: Path to receive output.\r
+ AppStderr: Path to receive error output.\r
+\r
+Parameters for CreateFile() are providing with the "AppStdinShareMode",\r
+"AppStdinCreationDisposition" and "AppStdinFlagsAndAttributes" values (and\r
+analogously for stdout and stderr).\r
+\r
+In general, if you want the service to log its output, set AppStdout and\r
+AppStderr to the same path, eg C:\Users\Public\service.log, and it should\r
+work. Remember, however, that the path must be accessible to the user\r
+running the service.\r
+\r
+\r
Removing services using the GUI\r
-------------------------------\r
NSSM can also remove services. Run\r
FreeConsole() fallita:
%2
.
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_CREATEFILE_FAILED
+Severity = Error
+Language = English
+CreateFile() failed to open %1:
+%2
+.
+Language = French
+CreateFile() a échoué %1:
+%2
+.
+Language = Italian
+Chiamata a CreateFile() fallita %1:
+%2
+.
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_DUPLICATEHANDLE_FAILED
+Severity = Error
+Language = English
+Error duplicating the filehandle previously opened for %1 as %2.
+DuplicateHandle() failed:
+%3
+.
+Language = French
+DuplicateHandle() a échoué (%1 -> %2):
+%3
+.
+Language = Italian
+Chiamata a DuplicateHandle() fallita (%1 -> %2):
+%3
+.
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_GET_OUTPUT_HANDLES_FAILED
+Severity = Error
+Language = English
+Error setting up one or more I/O filehandles. Service %1 will not be started.
+.
+Language = French
+Error setting up one or more I/O filehandles. Service %1 will not be started.
+.
+Language = Italian
+Error setting up one or more I/O filehandles. Service %1 will not be started.
+.
#include "messages.h"\r
#include "process.h"\r
#include "registry.h"\r
+#include "io.h"\r
#include "service.h"\r
#include "gui.h"\r
\r
</FileConfiguration>\r
</File>\r
<File\r
+ RelativePath=".\io.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath="nssm.cpp"\r
>\r
<FileConfiguration\r
>\r
</File>\r
<File\r
+ RelativePath=".\io.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath="nssm.h"\r
>\r
</File>\r
return get_number(key, value, number, true);\r
}\r
\r
-int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, char **env, unsigned long *throttle_delay) {\r
+int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, char **env, unsigned long *throttle_delay, STARTUPINFO *si) {\r
unsigned long ret;\r
\r
/* Get registry */\r
/* Try to get environment variables - may fail */\r
set_environment(service_name, key, env);\r
\r
+ /* Try to get stdout and stderr */\r
+ if (get_output_handles(key, si)) {\r
+ log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_OUTPUT_HANDLES_FAILED, service_name, 0);\r
+ RegCloseKey(key);\r
+ return 5;\r
+ }\r
+\r
/* Try to get throttle restart delay */\r
unsigned long type = REG_DWORD;\r
unsigned long buflen = sizeof(*throttle_delay);\r
#define NSSM_REG_ENV "AppEnvironment"\r
#define NSSM_REG_EXIT "AppExit"\r
#define NSSM_REG_THROTTLE "AppThrottle"\r
+#define NSSM_REG_STDIN "AppStdin"\r
+#define NSSM_REG_STDOUT "AppStdout"\r
+#define NSSM_REG_STDERR "AppStderr"\r
+#define NSSM_REG_STDIO_SHARING "ShareMode"\r
+#define NSSM_REG_STDIO_DISPOSITION "CreationDisposition"\r
+#define NSSM_REG_STDIO_FLAGS "FlagsAndAttributes"\r
+#define NSSM_STDIO_LENGTH 29\r
\r
int create_messages();\r
int create_parameters(char *, char *, char *, char *);\r
int expand_parameter(HKEY, char *, char *, unsigned long, bool);\r
int get_number(HKEY, char *, unsigned long *, bool);\r
int get_number(HKEY, char *, unsigned long *);\r
-int get_parameters(char *, char *, int, char *, int, char *, int, char **, unsigned long *);\r
+int get_parameters(char *, char *, int, char *, int, char *, int, char **, unsigned long *, STARTUPINFO *);\r
int get_exit_action(char *, unsigned long *, unsigned char *, bool *);\r
\r
#endif\r
\r
/* Get startup parameters */\r
char *env = 0;\r
- int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &env, &throttle_delay);\r
+ int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &env, &throttle_delay, &si);\r
if (ret) {\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_PARAMETERS_FAILED, service_name, 0);\r
return stop_service(2, true, true);\r
char cmd[CMD_LENGTH];\r
if (_snprintf(cmd, sizeof(cmd), "\"%s\" %s", exe, flags) < 0) {\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "command line", "start_service", 0);\r
+ close_output_handles(&si);\r
return stop_service(2, true, true);\r
}\r
\r
throttle_restart();\r
\r
- if (! CreateProcess(0, cmd, 0, 0, false, 0, env, dir, &si, &pi)) {\r
+ bool inherit_handles = (si.dwFlags & STARTF_USESTDHANDLES);\r
+ if (! CreateProcess(0, cmd, 0, 0, inherit_handles, 0, env, dir, &si, &pi)) {\r
unsigned long error = GetLastError();\r
if (error == ERROR_INVALID_PARAMETER && env) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED_INVALID_ENVIRONMENT, service_name, exe, NSSM_REG_ENV, 0);\r
else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service_name, exe, error_string(error), 0);\r
+ close_output_handles(&si);\r
return stop_service(3, true, true);\r
}\r
process_handle = pi.hProcess;\r
\r
if (get_process_creation_time(process_handle, &creation_time)) ZeroMemory(&creation_time, sizeof(creation_time));\r
\r
+ close_output_handles(&si);\r
+\r
/* Signal successful start */\r
service_status.dwCurrentState = SERVICE_RUNNING;\r
SetServiceStatus(service_handle, &service_status);\r