Iain Patterson [Tue, 4 Feb 2014 07:53:26 +0000 (07:53 +0000)]
Tidy up Edit Service buttons.
The French and Italian versions of Edit Service didn't fit as well as
the English version.
Iain Patterson [Mon, 3 Feb 2014 18:40:27 +0000 (18:40 +0000)]
Don't complain if the service has no ObjectName.
Not all service types run under an account.
Iain Patterson [Mon, 3 Feb 2014 18:30:25 +0000 (18:30 +0000)]
Format the exit action dropdown.
The longer messages didn't fully fit in the exit actions dropdown. Make
it wide enough to accommodate them.
Iain Patterson [Sun, 2 Feb 2014 23:21:44 +0000 (23:21 +0000)]
Credit for latest Italian translations.
Iain Patterson [Sun, 2 Feb 2014 23:19:05 +0000 (23:19 +0000)]
Removed redundant NSSM_EVENT_STDIN_CREATEPIPE_FAILED.
We aren't faking stdin with a pipe any longer so the message isn't
needed.
Iain Patterson [Sun, 2 Feb 2014 23:16:28 +0000 (23:16 +0000)]
Command arguments no longer called options.
The things appended to a program path in order to make a command line
are more appropriately called Arguments than Options.
Thanks Marco Certelli.
Marco Cartelli [Sun, 2 Feb 2014 23:15:52 +0000 (23:15 +0000)]
Latest Italian translations.
Signed-off-by: Iain Patterson <me@iain.cx>
Iain Patterson [Thu, 30 Jan 2014 20:49:43 +0000 (20:49 +0000)]
Use well-known account aliases.
Jump through a few hoops to make the Windows service control panel to
localise service ObjectNames if they are set to LocalSystem,
LocalService or NetworkService.
Those aren't the canonical names of the accounts as returned by
LsaLookupSids() so attempting to call ChangeServiceConfig() with a
username of, eg, NetworkService will fail, even though writing
NetworkService directly to the registry would work. Calling
ChangeServiceConfig() with a username of "NT Authority\Network Service"
will work, since that's the canonical name returned by LsaLookupSids()
but it won't be localised in the control panel.
The solution is to write "NT Authority\NetworkService" to the registry
and it will appear correctly.
At this point I'm not sure whether to label it a bug or a feature that
"nssm get <service> ObjectName" will return the actual value in the
registry and not the localised name.
Thanks Marco Certelli.
Iain Patterson [Wed, 29 Jan 2014 20:30:55 +0000 (20:30 +0000)]
Handle well-known account names.
Certain well-known accounts can be used to start a service without
entering a password.
"LocalSystem" is the default value of ObjectName in the registry. It is
not a real account but is an alias for the "NT Authority\System"
account.
"NT Authority\Local Service" has minimal local and no network
privileges.
"NT Authority\Network Service" has minimal local and network privileges.
NSSM now recognises these well-known accounts and will accept them as
ObjectName parameters without complaining that no password was enter.
With the exception of LocalSystem, each can be specified without the "NT
Authority" pseudo-domain prefix.
Iain Patterson [Tue, 28 Jan 2014 22:56:02 +0000 (22:56 +0000)]
Added CreateWellKnownSid and IsWellKnownSid imports.
Visual Studio 2008 doesn't recognise the functions so we need to load
them to the imports table.
Iain Patterson [Tue, 28 Jan 2014 22:42:37 +0000 (22:42 +0000)]
Fixed argument parsing for setting ObjectName.
Setting ObjectName needs a username and password, except when it
doesn't. We can't make the extra argument mandatory because it isn't.
Iain Patterson [Mon, 27 Jan 2014 22:28:55 +0000 (22:28 +0000)]
Correct label on file rotation GUI.
AppRotateBytes is, as the name implies, a measure of bytes. The GUI
incorrectly said kB.
Thanks Marco Certelli.
Iain Patterson [Mon, 27 Jan 2014 22:21:15 +0000 (22:21 +0000)]
Kill process tree from the top down.
On Windows 8.1 (and maybe other versions), attempting to kill
conhost.exe before its parent cmd.exe will cause the attempt to kill the
latter to fail and the console window to remain active after the service
ends.
We now kill the members of the process tree in reverse order, so the
problem doesn't occur.
Thanks Czenda Czendov.
Iain Patterson [Mon, 27 Jan 2014 22:17:45 +0000 (22:17 +0000)]
Ensure we have a valid service exit time.
Sometimes GetProcessTimes() will succeed but return 0 for the process
exit time, leading check_parent() to conclude that the service had
exited before a child process had started, and thus that the child
process was not part of the service's tree.
We now use initialise the service exit time to the current time before
attempting to get the real exit time, and only override the value if
it's valid.
Thanks Czenda Czendov.
Iain Patterson [Mon, 27 Jan 2014 21:13:31 +0000 (21:13 +0000)]
Send Control-C to the right window.
We were always trying to send Control-C to the console of the parent
process rather than any subprocesses found in kill_process_tree().
Iain Patterson [Mon, 27 Jan 2014 19:05:46 +0000 (19:05 +0000)]
Enough with the small buffers already.
Sledgehammer, meet nut.
Iain Patterson [Mon, 27 Jan 2014 18:46:32 +0000 (18:46 +0000)]
Fixed service context detection when built with VS2013.
Visual Studio 2013 includes a C runtime which assigns stdin, stdout and
stderr the file descriptors 0, 1 and 2 - just like UNIX does - even if
there are no streams available. Thus we can no longer use "_fileno(stdin)
< 0" as a check for running in a service context.
Instead we check for "GetStdHandle(STD_INPUT_HANDLE) == 0" which works
when compiled with older or newer versions of Visual Studio.
Thanks Czenda Czendov.
Iain Patterson [Sun, 26 Jan 2014 16:22:26 +0000 (16:22 +0000)]
Don't expand parameters when editing a service.
Environment variables were still being expanded when retrieving strings
to display in the GUI.
Iain Patterson [Sun, 26 Jan 2014 16:12:11 +0000 (16:12 +0000)]
Really fix warning when file disposition isn't set.
If AppStdoutDisposition and AppStderrDisposition are both missing from
the registry, the service editing GUI would still incorrectly complain
that the current configuration couldn't be represented in the interface
even though a previous commit claimed to fix that.
Iain Patterson [Sun, 26 Jan 2014 14:11:57 +0000 (14:11 +0000)]
Split get_output_handles() into get_io_parameters().
Separate retrieving parameters from the registry and opening output
handles.
Restart throttling happens after calling get_output_handles(), so if the
service was throttled we'd end up with a useless console window
appearing during the pause.
Iain Patterson [Sun, 26 Jan 2014 14:21:41 +0000 (14:21 +0000)]
Moved console functions to a new file.
Functions for allocating and setting up a console are moved to
console.cpp.
Iain Patterson [Sat, 25 Jan 2014 21:45:56 +0000 (21:45 +0000)]
Allocate new console by default.
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.
Iain Patterson [Sat, 25 Jan 2014 21:59:57 +0000 (21:59 +0000)]
Allocate a new console for stdin.
Allocate a new console for processes which require stdin instead of
using the pipe hack.
Iain Patterson [Sat, 25 Jan 2014 11:22:11 +0000 (11:22 +0000)]
Fixed CreateFile() flags when opening log files.
Opening a file with FILE_APPEND_DATA access is not appropriate when not
truncating existing files or opening new files. Redirected I/O would be
buffered and output would not be immediately visible to readers.
Iain Patterson [Thu, 23 Jan 2014 21:19:32 +0000 (21:19 +0000)]
Revamped environment variables again.
A previous commit changed how environment variables were managed.
Initially we were calling SetEnvironmentVariable() on each variable
defined in AppEnvironmentExtra prior to starting the service. That
behaviour was changed because it was technically incorrect, potentially
resulting in NSSM's own environment being harmed.
Unfortunately the changed method, creating a new environment block by
calling GetEnvironmentStrings() (or using the block from AppEnvironment
if that and AppEnvironmentExtra were both defined), failed if users did
something like set AppEnvironmentExtra to PATH=C:\bin;%PATH%. That
would result in the process being started with a block which included
TWO occurrences of the PATH variable; the system-defined one and the
appended one. The latter would be ignored, possibly causing the
application to fail to start.
For this third attempt we now call GetEnvironmentStrings() once at
startup, storing the block in a new variable which is only freed at
exit. Immediately prior to calling CreateProcess() to start the service
we use the new environment functions duplicate_environment() (on
AppEnvironment) and set_environment_block() (on AppEnvironmentExtra) to
set the variables. Then immediately after calling CreateProcess() we
call duplicate_environment() again to restore the original block.
Because they are passed to expand_environment_string(), the environment
blocks are subject to expansion. That means that setting PATH as
described in the example above would work. Trying to append items to
the PATH by setting AppEnvironment in a similar way will probably not
work.
Thanks Bryan Senseman.
Iain Patterson [Thu, 23 Jan 2014 21:12:43 +0000 (21:12 +0000)]
Added more environment functions.
useful_environment() skips the uninteresting variables at the start of
an environment block, returning a pointer to the first useful variable.
expand_environment_string() expands a string with
ExpandEnvironmentStrings() and returns a pointer to the expanded string,
which must be freed after use.
set_environment_block() iterates through all the variables in an
environment block, expands each one with expand_environment_string() and
calls SetEnvironmentVariable() with the expanded value.
clear_environment() removes all variables from the current environment.
duplicate_environment() duplicates an environment block by first calling
clear_environment() then set_environment_block() with the source block.
Thus it ensures that the variables in the block - and only those - are
set in the current environment.
Iain Patterson [Thu, 23 Jan 2014 20:06:54 +0000 (20:06 +0000)]
Renamed set_environment().
The set_environment() function was poorly named. It gets the
environment settings from the registry but doesn't actually set any
variables. It is more appropriately named get_environment().
Iain Patterson [Thu, 23 Jan 2014 20:05:25 +0000 (20:05 +0000)]
Moved environment functions to a new file.
Moved format_environment(), unformat_environment() and
test_environment() to env.cpp.
Iain Patterson [Wed, 22 Jan 2014 22:21:09 +0000 (22:21 +0000)]
Fixed warning when file disposition isn't set.
If AppStdoutDisposition and AppStderrDisposition are both missing from
the registry, the service editing GUI would incorrectly complain that
the current configuration couldn't be represented in the interface.
Iain Patterson [Sun, 19 Jan 2014 22:35:54 +0000 (22:35 +0000)]
Minor vcproj tidying.
Consistent file naming via the RelativePath attribute.
Iain Patterson [Sun, 19 Jan 2014 18:01:36 +0000 (18:01 +0000)]
Fake stdin for applications which exit on EOF.
Some applications, like MonetDB server, expect to read commands on
stdin. If they read a keyword, usually "exit" or "quit" or if stdin is
closed, they will exit.
Such applications will typically work when run in a service context via
NSSM, as Windows will allocate a console window for them. However, when
the service is configured to redirect stdout and/or stderr but not
stdin, the application will exit immediately because it will see no
input and think that the user closed stdin.
To deal with this situation we interpret an AppStdin value of "|" (a
single pipe character) as requesting a hack mode whereby we open a pipe
and pass the reading end to the application as the stdin handle. We
never actually write anything to the writing end of pipe but simply keep
it around until the application exits or the service receives a stop
control. Closing the pipe on receipt of a stop request may even be
sufficient to close the application gracefully without resorting to any
of the other stop methods.
As an aside, MonetDB server can be run in batch mode, wherein it does
not attempt to read from stdin at all. The hack is not necessary for it
or other applications with similar functionality.
Thanks Bryan Senseman.
Iain Patterson [Sun, 19 Jan 2014 17:27:28 +0000 (17:27 +0000)]
Don't fail to restart if the service is stopped.
Treat a restart control on a stopped service as a start control.
Iain Patterson [Sun, 19 Jan 2014 17:12:52 +0000 (17:12 +0000)]
Fixed NSSM_EVENT_DUPLICATEHANDLE_FAILED message.
We were supposed to add a parameter explaining which handle couldn't be
duplicated.
Iain Patterson [Sat, 18 Jan 2014 13:43:06 +0000 (13:43 +0000)]
Fixed regression in file browser.
The GUI file browser was the only place in the code we were using new
and delete[] instead of HeapAlloc() and HeapFree().
The previous commit overlooked that fact and introduced a compiler error
by assuming that lpstrFile was a buffer of a known size instead of being
allocated with new.
Fix the regression and use HeapAlloc()/HeapFree() for consistency.
Iain Patterson [Wed, 15 Jan 2014 21:27:32 +0000 (21:27 +0000)]
Adjust buffer sizes.
Unicode applications can under certain circumstances access paths longer
than MAX_PATH characters. Service names are limited to 256 characters.
Adjust our buffers to suit.
Iain Patterson [Wed, 15 Jan 2014 21:24:24 +0000 (21:24 +0000)]
French CPUs are UCs.
Unité Centrale.
Iain Patterson [Tue, 14 Jan 2014 23:07:38 +0000 (23:07 +0000)]
Fixed drawing of rotation GUI labels.
The "Restrict rotation" labels were slightly too large, resulting in
them bleeding into the associated editboxes if the window were redrawn.
Iain Patterson [Tue, 14 Jan 2014 23:05:58 +0000 (23:05 +0000)]
Don't expand parameters when querying a service.
Calling, eg "nssm get <service> Application" should print the unexpanded
string from the registry.
Iain Patterson [Tue, 14 Jan 2014 23:04:55 +0000 (23:04 +0000)]
Added get_string() and set_string().
Abstract expand_parameter() and set_expand_string() to allow working
with registry values of type REG_SZ as well a REG_EXPAND_SZ.
Iain Patterson [Mon, 13 Jan 2014 23:53:33 +0000 (23:53 +0000)]
Fixed regression with offline rotation.
We weren't falling through to direct I/O when online rotation was
completely disabled, only when it was attempted but failed.
We weren't closing pipe handles after a failed attempt to enable online
rotation.
We were incorrectly complaining about I/O errors in the event log when the
application was exiting.
Iain Patterson [Mon, 13 Jan 2014 23:13:30 +0000 (23:13 +0000)]
Formatting.
Iain Patterson [Mon, 13 Jan 2014 23:11:45 +0000 (23:11 +0000)]
Tidy up online rotation.
Move the messy copy/paste of the logging thread setup into a separate function.
No longer incorrectly tread longs as bools.
Fixed some typos and incorrect logic.
Iain Patterson [Mon, 13 Jan 2014 15:56:14 +0000 (15:56 +0000)]
s/stdout/stderr/
Again...
Iain Patterson [Mon, 13 Jan 2014 12:11:07 +0000 (12:11 +0000)]
Allow restarting a service.
Running "nssm restart <service>" will try to send a stop control
followed by a start control. It will fail if the service was stopped at
the outset or if it didn't respond to the stop control in a timely
manner.
Iain Patterson [Mon, 13 Jan 2014 12:08:17 +0000 (12:08 +0000)]
Don't get stuck in SERVICE_CONTINUE_PENDING.
If we received SERVICE_CONTROL_CONTINUE and the service wasn't paused we
would incorrectly set SERVICE_CONTINUE_PENDING status.
The Windows services console won't allow a user to attempt to send a
continue control to a running service but other applications, like say
NSSM itself, might happily try, then get confused when the status wasn't
set to SERVICE_RUNNING.
Iain Patterson [Mon, 13 Jan 2014 11:56:53 +0000 (11:56 +0000)]
More robust options for controlling a service.
Wait for the service status to change, eg from START_PENDING to RUNNING
before deciding whether a service control operation was successful.
Iain Patterson [Mon, 13 Jan 2014 11:09:54 +0000 (11:09 +0000)]
Added service_status_text().
Function to get a string representation of a service status, eg
SERVICE_RUNNING.
Iain Patterson [Mon, 13 Jan 2014 09:33:30 +0000 (09:33 +0000)]
Added fake NSSM_SERVICE_CONTROL_START constant.
There's no SERVICE_CONTROL_START constant so we were explicitly checking
for a fake control code of 0 when handling service start. Now that we
have defined a custom control code (NSSM_SERVICE_CONTROL_ROTATE) we can
add NSSM_SERVICE_CONTROL_START for readability and consistency.
Iain Patterson [Mon, 13 Jan 2014 09:30:52 +0000 (09:30 +0000)]
Added error message for missing subparameter.
Clarify the output when editing a service on the command line and a
mandatory subparameter was not supplied.
Thanks Chris Blaszczynski.
Iain Patterson [Sun, 12 Jan 2014 23:56:10 +0000 (23:56 +0000)]
Enable on-demand rotation.
Running "nssm rotate <service>" will send user-defined service control
128 to the service, triggering a rotation of output files after the next
call to ReadFile(), regardless of the value of AppRotateBytes*.
Note that since ReadFile() is synchronous, we have no way to interrupt
it, hence there may be a significant delay before the rotation happens.
Iain Patterson [Sun, 12 Jan 2014 23:02:23 +0000 (23:02 +0000)]
Fixed copy/paste bug with I/O.
The stderr file was incorrectly being created with stdout paramters.
Iain Patterson [Sun, 12 Jan 2014 22:59:37 +0000 (22:59 +0000)]
More robust online rotation.
Try to differentiate between fatal and non-fatal I/O errors. Give up on
logging only as a last resort. Clean up logger data properly. Report
when a file was rotated.
Iain Patterson [Sun, 12 Jan 2014 19:27:02 +0000 (19:27 +0000)]
Bigger I/O buffer.
We set a small logging buffer size when testing. The buffer should be
bigger for a final release.
Iain Patterson [Sat, 11 Jan 2014 11:46:42 +0000 (11:46 +0000)]
Rotate files while the service is running.
If AppRotateOnline is set, set up a pipe between the application's
stdout/stderr and a new thread which reads all input and writes to the
configured output file(s).
If a file breaches the configured AppRotateBytes threshold while the
service is running, close and rotate the file then resume logging to
a new file.
This behaviour is not the default due to the potential for things to go
wrong. We have to juggle file handles and might hit a read or write
error which causes logging to fail thus losing all output until the
service is restarted, etc etc.
Thanks Doug Watson.
Iain Patterson [Fri, 10 Jan 2014 23:27:54 +0000 (23:27 +0000)]
Write canonical AppExit string.
If the user ran "nssm set <servicename> AppExit Default exit" the
default value of AppExit would be set verbatim to "exit" which is in
contrast the documented value "Exit" with normal capitalisation.
There's no harm to that fact, as AppExit is retrieved case-insensitively
but it was nonetheless not working as intended.
Iain Patterson [Thu, 9 Jan 2014 18:27:00 +0000 (18:27 +0000)]
Copy environment block rather than setting extra variables.
If AppEnvironmentExtra is configured we were calling
SetEnvironmentVariable() to append each one to the existing environment.
That's arguably wrong as it could mess up NSSM's own environment.
Instead we now call GetEnvironmentStrings() and take a copy of the
current environment ebfore appending the extra environment as we were
doing before.
Iain Patterson [Thu, 9 Jan 2014 09:56:24 +0000 (09:56 +0000)]
Force UTF-16 output.
If we were compiled as a Unicode application, set stdout and stderr
output mode to UTF-16 text. Doing so allows French and Italian accented
characters to show up correctly on the console.
We currently have no analogous method for fixing the output of NSSM when
compiled as an ANSI application.
Iain Patterson [Thu, 9 Jan 2014 08:56:22 +0000 (08:56 +0000)]
More compiler food.
Om nom nom.
Iain Patterson [Thu, 9 Jan 2014 08:53:32 +0000 (08:53 +0000)]
Added mandatory restart delay.
The REG_DWORD AppRestartDelay entry specifies a minimum number of
milliseconds by which we will delay the restart (not the initial start)
of the managed application. If the application exited soon enough to
trigger throttling, the actual delay will be whichever is longer of
AppRestartDelay and the calculated throttle time.
Thanks Andrew RedzMax.
Iain Patterson [Wed, 8 Jan 2014 14:55:59 +0000 (14:55 +0000)]
Allow setting processor affinity.
The REG_SZ AppPriority entry specifies a list of processors which will
be converted to a mask and passed to SetProcessAffinityMask().
Processors are numbered from 0, must not exceed 63, and are separated
with commas or dashes, to specify a range.
Thanks Robert Middleton.
Iain Patterson [Tue, 7 Jan 2014 10:09:20 +0000 (10:09 +0000)]
AppPriority is an optional parameter.
We were incorrectly requiring its presence and logging an error when it
wasn't found. The parameter was not intended to be mandatory and no
error should be logged unless the parameter is present but invalid.
Iain Patterson [Tue, 7 Jan 2014 19:02:36 +0000 (19:02 +0000)]
Overload str_number().
Allow passing the bogus pointer to str_number() in case we want to
inspect it later.
Iain Patterson [Mon, 6 Jan 2014 18:22:07 +0000 (18:22 +0000)]
Corrected priority documentation.
The correct function name is SetPriorityClass() not
SetProcessPriorityClass().
Iain Patterson [Mon, 6 Jan 2014 18:17:07 +0000 (18:17 +0000)]
Fixed year marker in build information.
The year wasn't being set reliably by version.cmd.
Iain Patterson [Mon, 6 Jan 2014 17:28:24 +0000 (17:28 +0000)]
Allow setting application priority.
The REG_DWORD AppPriority entry corresponds to a priority class as
accepted by SetProcessPriorityClass(). If a valid value is set, it will
be passed to CreateProcess() and the application will start with the
requested priority.
Iain Patterson [Mon, 6 Jan 2014 16:52:16 +0000 (16:52 +0000)]
Fixed message when RegSetValueEx() fails.
We were incorrectly displaying the error message associated with
RegDeleteValue().
Iain Patterson [Mon, 6 Jan 2014 11:17:35 +0000 (11:17 +0000)]
Basic system translations.
Copy translations for the Details and Log on tabs from native Windows
tools.
Iain Patterson [Sat, 4 Jan 2014 16:17:07 +0000 (16:17 +0000)]
Give up on older Visual Studio versions.
Tests show that Visual Studio 6 and 2005 won't build NSSM presumably
because there is no suitable platform SDK corresponding to those versions.
Carting around a legacy DSP and DSW file is therefore somewhat
pointless, especially as newer Visual Studio releases have freely
available Express versions and will compile the project.
Iain Patterson [Sat, 4 Jan 2014 11:23:52 +0000 (11:23 +0000)]
Added messages to Visual Studio 6 workspace.
Added the messages.mc file was added to the workspace.
It's of limited usefulness given that the project won't build...
Iain Patterson [Sat, 4 Jan 2014 10:48:22 +0000 (10:48 +0000)]
More appropriate LegalCopyright field.
It doesn't make a lot of sense to have a Copyright notice on a Public
Domain work. The intention of including the LegalCopyright version
string was solely to assert authorship. The new string should make that
clearer.
Iain Patterson [Wed, 1 Jan 2014 23:23:48 +0000 (23:23 +0000)]
ANSI compiler food.
Iain Patterson [Wed, 1 Jan 2014 22:07:11 +0000 (22:07 +0000)]
Extra product description tags.
Call ourselves NSSM not nssm. Add 32/64-bit and release/debug specifiers.
Since we are adding them to the resource files as well we need to add the
_WIN64 preprocessor definition to the resources definition list explicitly.
To ensure that messages sent to the event log remain consistent we
define the event source separately and set it to the old lowercase name.
Iain Patterson [Wed, 1 Jan 2014 21:44:48 +0000 (21:44 +0000)]
Fixed bugs when creating a service.
A null argument to grant_logon_as_service() would cause a crash.
We were calling CreateService() with the wrong access mask.
We weren't printing any error message when CreateService() failed.
Iain Patterson [Wed, 1 Jan 2014 18:49:06 +0000 (18:49 +0000)]
Legacy quick'n'dirtiness.
On Windows 2000, StartService() and ControlService() return
ERROR_IO_PENDING immediately. Later versions of Windows have a
builtin timeout before they will return that error.
As far as we're concerned, ERROR_IO_PENDING indicates that the service
control was sent successfully so we simply override the error and
return success.
If NSSM's service management functionality is ever expanded we can take
the time to handle service controls in a more robust way.
Iain Patterson [Wed, 1 Jan 2014 16:05:52 +0000 (16:05 +0000)]
Allow querying a service's name.
Since we can now open a service by its display name it may be
interesting to know what its canonical name is.
Find out with:
nssm get <displayname> Name
Iain Patterson [Wed, 1 Jan 2014 16:00:17 +0000 (16:00 +0000)]
Added open_service().
New function to open a service either by name or display name. Since no
service's display name may conflict with any other service's display
name or key name, we can safely use a display name as a key when opening
a service.
OpenService() expects a service name so if it fails with status
ERROR_SERVICE_DOES_NOT_EXIST we can enumerate all services and look for
one whose display name matches the argument passed to open_service(),
and open it. As a side effect we can optionally store the canonical
name in a separate (or not) buffer.
Iain Patterson [Wed, 1 Jan 2014 15:14:51 +0000 (15:14 +0000)]
Allow controlling services.
Send start/stop/query messages to services is easy so adding the ability
to do so is a quick win.
Iain Patterson [Wed, 1 Jan 2014 12:41:02 +0000 (12:41 +0000)]
Allow service editing on the command line.
Individual service parameters can now be queried or edited on the
command line. The syntax is designed to be intuitive and is
described in some detail in the README. Some examples follow:
nssm get Selenium Application
nssm get "My Batch Job" AppExit 0
nssm get Jenkins AppEnvironmentExtra CLASSPATH
nssm get Netlogon ImagePath
nssm set UT2004 Application C:\Games\UT2004\System\UCC.exe
nssm set UT2004 AppParameters server
nssm set UT2004 AppExit Default Exit
nssm set Jenkins ObjectName DOMAIN\ci correct horse battery staple
nssm set "My Batch Job" AppExit 0 Exit
nssm set WowzaMediaServer362 Start SERVICE_DELAYED_START
nssm set UT2004 Type SERVICE_INTERACTIVE_PROCESS
nssm reset UT2004 AppEnvironment
nssm reset UT2004 ObjectName
Iain Patterson [Wed, 1 Jan 2014 12:39:20 +0000 (12:39 +0000)]
Added str_number().
Wrapper function around _tcstoul().
Iain Patterson [Wed, 1 Jan 2014 12:37:07 +0000 (12:37 +0000)]
Be more Windowsy.
Now that the GUI is more functional, it should behave more like a real
Windows application. That means having an icon and modal messageboxes.
Iain Patterson [Wed, 1 Jan 2014 12:02:06 +0000 (12:02 +0000)]
Fixed srvany-compatible environment checkbox.
The checkbox was inverted. If we were replacing the environment, like
srvany does, it was unchecked, suggesting that the environment would be
appended.
Iain Patterson [Wed, 1 Jan 2014 12:00:33 +0000 (12:00 +0000)]
Added format_environment() and unformat_environment().
Added new functions to convert an environment block, with each KEY=value
pair separated by NULL NULL, to and from a string, with the pairs
separated by CRLF.
Iain Patterson [Tue, 31 Dec 2013 16:11:08 +0000 (16:11 +0000)]
Added get_service_description().
New function to set or unset a service's description.
Iain Patterson [Tue, 31 Dec 2013 14:04:00 +0000 (14:04 +0000)]
Added open_registry() function.
Moved RegOpenKeyEx() and RegCreateKeyEx() to a separate function
open_registry().
Iain Patterson [Mon, 30 Dec 2013 13:55:18 +0000 (13:55 +0000)]
Added get_service_username().
New function to get the service username.
Iain Patterson [Mon, 30 Dec 2013 13:43:15 +0000 (13:43 +0000)]
Added get_service_description().
New function to get the service description.
Iain Patterson [Mon, 30 Dec 2013 11:50:20 +0000 (11:50 +0000)]
Added get_service_startup().
New function to retrieve the service startup type.
Iain Patterson [Mon, 30 Dec 2013 11:20:07 +0000 (11:20 +0000)]
Remember to free info after QueryServiceConfig2().
We weren't freeing the SERVICE_CONFIG_DELAYED_AUTO_START_INFO buffer
after checking for delayed auto start.
Iain Patterson [Mon, 30 Dec 2013 10:56:19 +0000 (10:56 +0000)]
Moved QueryServiceConfig() to a separate function.
The new function query_service_config() will return a pointer to a
QUERY_SERVICE_CONFIG data structure.
Iain Patterson [Sun, 29 Dec 2013 17:29:21 +0000 (17:29 +0000)]
Detect if we were double-clicked.
Because we are compiled as a console subsystem application, if the user
double-clicks the executable it will pop up a new console window. Then,
since no arguments were passed, we will dump a usage message which the
user won't have time to read, and exit.
We now detect this situation and redirect the usage message to a popup.
There are three likely cases to handle.
If we are running in a service context there won't be a console window.
GetConsoleWindow() will return a null handle.
If were launched from a command window, the process ID owning the
console handle will be different from as our process ID.
If the process IDs are the same, we were started with a new console. We
call FreeConsole() to close it and subsequently direct the usage message
to a message box.
Iain Patterson [Sun, 29 Dec 2013 17:25:54 +0000 (17:25 +0000)]
Fixed loading localised resources.
We weren't loading the correct resources for non-English languages when
compiled as a Unicode application.
We now explicitly call FindResourceEx(), LoadResource() and
CreateDialogIndirectParam() to ensure the appropriate windows are shown.
We now explicitly pass GetUserDefaultLangID() to FormatMessage(),
falling back to language neutral if it fails.
Resources and messages are now explicitly UTF-16LE. That means that git
will treat them as binary and refuse to diff them. To work around that,
add the following to .git/info/attributes:
*.mc diff=utf16
*.rc diff=utf16
and the following to .git/config:
[diff "utf16"]
textconv = "iconv -f utf-16le -t utf-8"
Iain Patterson [Sat, 28 Dec 2013 17:02:30 +0000 (17:02 +0000)]
Fixed arguments to mbstowcs_s().
The third argument to mbstowcs_s() is a buffer size not a character
count.
Iain Patterson [Sat, 28 Dec 2013 16:41:06 +0000 (16:41 +0000)]
Grant SeServiceLogonRight.
If the service is to be run under a user account, ensure that the
account has the right to log on as a service.
Iain Patterson [Sat, 28 Dec 2013 16:33:38 +0000 (16:33 +0000)]
Fixed print_message() when out of memory.
We were passing NSSM_EVENT_OUT_OF_MEMORY to print_message() but
print_message() expects printf-style message strings and NSSM_EVENT_*
strings use %1, %2 etc. Instead we now use the new message
NSSM_MESSAGE_OUT_OF_MEMORY when printing memory errors to the console.
Iain Patterson [Sat, 28 Dec 2013 16:30:42 +0000 (16:30 +0000)]
Fixed changing service password.
Ensure that we still process a password change even if the username is
the same.
Ensure we handle all errors from edit_service().
Iain Patterson [Sat, 28 Dec 2013 16:13:34 +0000 (16:13 +0000)]
Safer version.h creation.
Use a temporary file so Visual Studio doesn't detect a timestamp change
on the file and trigger a rebuild.
Iain Patterson [Fri, 27 Dec 2013 14:15:21 +0000 (14:15 +0000)]
More detailed file properties.
Add build information, comments and copyright to the executable's
version info fields.
Iain Patterson [Thu, 26 Dec 2013 19:30:47 +0000 (19:30 +0000)]
Generate version information as part of the build.
Use git (if it's available) to create a major and minor version number
based on the most recent tag name. If we are not building from a
tagged commit, use the commit count since the last tag as the subminor
version. If Jenkins is being used for the build, use the build number
as the subsubminor version.
Iain Patterson [Thu, 26 Dec 2013 19:28:56 +0000 (19:28 +0000)]
Display canonical service name.
When editing or deleting a service we get the service information using the
name provided by the user. The name is case-insensitive but case-preserving.
Use GetServiceKeyName() to retrieve the canonical name and display that
in any messages containing the service name.
Iain Patterson [Mon, 23 Dec 2013 18:25:28 +0000 (18:25 +0000)]
Allow editing services.
"nssm edit <service>" brings up a GUI to edit an existing service.
Services not managed by NSSM can also be edited but only system
properties such as the display name will appear in the GUI.