Services are also regularly run on different account especially the ones under "NT AUTHORITY" like "SYSTEM" and "NETWORK SERVICE".
As I recall Visual Studio contains some pretty good templates for writing services with C# but the underlying requirements are abstracted by the .net Framework.
IMO a lot of parts of Windows are a pain to develop on compared to Linux, but creating and managing services are one of the better/smoother parts.
Now depending on what you actually want to do, you have some options:
- Use the Windows Services API to ask Windows to start and manage your process as a system service - this is closest to a SystemD demon
- Create a GUI process with WindowStyle=hidden (this will be part of the current user's session)
- Create a Console process with the DETACHED_PROCESS flag, which should work similarly to the above
- Use one of the CreateProcessAsUser() family of functions to create a process for another user - this should allow the process to run in the background, and allow it to persist even if the current user signs off
In all cases above, you can simply tell CreateProcess* that the child process should not inherit any FDs. You should probably also use the PROC_THREAD_ATTRIBUTE_PARENT_PROCESS flag to spawn this process as the child of some other long-running process, to ensure that the child process is not part of the same Job that the current process may be (usually, when a Job is finished, all processes in that job and any child they spawned, recursively, are killed).
On Linux, it turned out to be surprisingly tricky. Process groups and sessions are not nested, you can easily break out of them and in fact there were some programs we needed to use that insisted on doing daemonization. Thankfully the most important one had a "--foreground" flag but it still was buggy: this program sends SIGTERM to its process group as part of a shutdown — so it kills its parent, too. Amazing. In the end I believe we ended running each worker process as a separate Docker container.
Then there is a dance of waiting (or not waiting? SIGCHILD is truly horrible) on children PIDs to detect the crashes and unexpected hang in the shutdown (the worker process sends "I am done" notification to the parent, but then for some reason doesn't exit). The main process had to be made a sub-reaper to do all of that more or less reliably, and even then there were some strange sightings (signal handling is fun!).
On Windows, we just shoved each worker process into its own unbreakable-from job, and that was it. The main process dies for whatever reasons, its children just disappear. A worker process dies, its children just disappear, without affecting any other worker processes and their children. Detecting termination of the child processes too was a breeze: on Windows, when you spawn a child process you get not only its PID, but also a handle (think "file descriptor") to it. This handle refers exactly to this process, and you can (interruptibly) wait on it, and when the last open descriptor to a process is closed, the process is deleted from the process table. That's why BTW there is no PID 1 that is constantly reaping its children on Windows: each process implicitly has its own handle alway open, so if the parent exits before the child does, nothing bad happens: The child process had 2 open handles on it, now it has 1. When it itself exits, the last handle is dropped, and the slot in the process table is cleaned.
TL;DR: Process management is horrible, use Erlang.
https://docs.microsoft.com/en-us/dotnet/framework/windows-se...
I suspect there's not a lot of Win-dev folks on HN.
How is a service started? The SCM launches the specified executable, in the way it's specified in the service's settings and... that's pretty much it.
However, the service is supposed to support a certain protocol of interaction with SCM. First of all, the service must quickly (within half a minute from the start, IIRC) call the WinAPI function StartServiceCtrlDispatcher() on its main thread. That's basically a pre-written main(): it returns only after the service has been stopped. It takes several function pointers: to the ServiceMain where the service proper is supposed to be, and various event handlers (pause/resume/stop requests, system is shutting down, etc). It creates a separate thread to run the ServiceMain on, and then basically loops processing requests/events from the SCM (event handlers are run on the main thread).
That's basically it. Nothing prevents one to write an application that can run both as a service and stand-alone: put your logic in ServiceMain, call StartServiceCtrlDispatcher with it, if it returns ERROR_FAILED_SERVICE_CONTROLLER_CONNECT (that means you're not being launched by the SCM), call ServiceMain by yourself. Ctrl-C handler and "stop the service" handler are easily unified because on Windows, Ctrl-C handler always runs on a different thread. You just need make sure that your ServiceMain function can be safely signaled that it needs to stop from a different thread, but that's what thread-communication primitives are for.