C#/.NET: Detect whether program is being run as a service or a console application [duplicate]

StackOverflow https://stackoverflow.com/questions/207896

  •  03-07-2019
  •  | 
  •  

Question

This question already has an answer here:

I have a C#/.NET program that can run both as a console application and as a service. Currently I give it a command-line option to start as a console application, but I would like to avoid that.

Is it possible to programmatically detect whether my program is being started as a service?

If it was pure Win32, I could try starting as a service with StartServiceCtrlDispatcher and fall back to console if it returned ERROR_FAILED_SERVICE_CONTROLLER_CONNECT, but System.ServiceProcess.ServiceBase.Run() pops up an errordialog if it fails and then just returns without signaling an error to the program.

Any ideas?

Was it helpful?

Solution

Rasmus, this is the earlier question.

From the answers it seems the most popular way is to use a simple command line option, or try accessing the Console object in a try catch block (in a Service the Console is not attached to the process and trying to access it throws an exception).

Or if you're having trouble testing/debugging the service, move code into a separate dll assembly and create a seprate test harness (winforms/console etc).

(Just noticed that Jonathan has added his solution to the end of the question.)

OTHER TIPS

Environment.UserInteractive will do the magic.

Might want to try SessionId property of the Process object. In my experience SessionId is set to 0 if the process is running a service.

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
const int STD_OUTPUT_HANDLE = -11;

IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

if (iStdOut == IntPtr.Zero)

{    
    app.RunAsWindowsService = true;

}

// Run as Service
if (runAsWindowsService)                                
{
     // .....
     ServiceBase.Run(myService);
}
else 
{
    // Run as Console
    // Register Ctrl+C Handler...
}

Using the ParentProcessUtilities struct from this answer about finding a parent process, you can do this:

static bool RunningAsService() {
    var p = ParentProcessUtilities.GetParentProcess();
    return ( p != null && p.ProcessName == "services" );
}

Note that the process name for the parent process does not include the extension ".exe".

I haven't tried it, but it's possible that Process.GetCurrentProcess will help - under console mode the process name would be the same as the executable, whereas I'd expect (and again, please check!) that when running as a service it would be different.

I don't know if this will work, but you may want to try using PInvoke with this code and checking if the parent is "services.exe".

I ended up detecting whether or not I was in a console application by checking Console.IsErrorRedirected. It returned "false" for console apps, and "true" for the non-console apps I tested. I could have also used IsOutputRedirected.

I imagine there are circumstances where these will not be accurate, but this worked well for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top