27

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?

Rasmus Faber
  • 48,631
  • 24
  • 141
  • 189
  • Maybe the OP didn't know this was a dupe because the question that was already answered has a terrible name. – rory.ap Jan 09 '18 at 19:08

8 Answers8

36

Environment.UserInteractive will do the magic.

Vlad Nagorny
  • 385
  • 3
  • 2
7

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.)

Community
  • 1
  • 1
Ash
  • 60,973
  • 31
  • 151
  • 169
7

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.

Curt Williams
  • 163
  • 2
  • 7
  • 1
    This method is simple, fast and reliable. It won't tell you if your process *is* the service, or merely being run as a child of a service, but this does work (note that it only works on Vista and above - prior to that the first user log-in session would also be session ID zero and shared with the services). – Alastair Maw Mar 23 '18 at 17:48
3

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".

Community
  • 1
  • 1
Dylan Nissley
  • 594
  • 1
  • 5
  • 12
3

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I thought that the process was still (usually) the same exe itself, unless you go out of your way to rehost via svchost.exe or similar... – Marc Gravell Oct 16 '08 at 11:56
  • Could be - hard to test from my current desk :( – Jon Skeet Oct 16 '08 at 14:12
  • At least under mono, the process name does change to the executing entity (i.e. if run with mono-service the process is now called mono-service). Haven't tried as a windows service – Arne Claassen Dec 01 '08 at 19:21
3
[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...
}
Andrei Sfat
  • 8,440
  • 5
  • 49
  • 69
Chin Siang
  • 39
  • 1
1

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".

ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
0

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.

NightShovel
  • 3,032
  • 1
  • 31
  • 35
  • IsOutputRedirected will be true if the console application is started from the console and output is redirected or piped (> or |). – codeape Nov 29 '16 at 12:14