How to determine if a Windows service starts inside?

I am currently checking it as follows:

if (Environment.UserInteractive) Application.Run(new ServiceControllerForm(service)); else ServiceBase.Run(windowsService); 

This helps debug a bit, and maintenance can also be started using an executable. But suppose service requires interaction with the user's desktop, so I need to enable "Allow service to interact with the desktop" in the properties. This, of course, violates this verification method. Is there another way?

+5
c # windows-services
source share
6 answers

This is not ideal, but you could probably do something like this:

 public static bool IsService() { ServiceController sc = new ServiceController("MyApplication"); return sc.Status == ServiceControllerStatus.StartPending; } 

The idea is that if you run this while your service is still running, it will always be on hold. If the service is not installed at all, the method will always return false. In a very unlikely edge case, this will lead to a service failure, and someone is trying to start it as an application at the same time.

I don't like this answer, but I think this is probably the best you can do. It’s really not a good idea to allow the same application to work in the service or application mode - in the end it will be easier if you draw all the common functions in the class library and just create a separate service application. But if for some reason you really need to have your cake and eat it, you can probably combine the IsService method above with Environment.UserInteractive to get the right answer almost all the time.

+6
source share

The problem with the accepted answer is that checking the status of a service that is not installed will throw. The IsService method that I use is as follows:

  private bool IsService(string name) { if (!Environment.UserInteractive) return true; System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(name); try { return sc.Status == System.ServiceProcess.ServiceControllerStatus.StartPending; } catch(InvalidOperationException) { return false; } } 

What should work more reliably than just checking Environment.UserInteractive

+4
source share

Why not just use the command line switch?

 // Note that you have to add the params argument, // which isn't usually present in windows services private static void Main(params string[] parameters) { .... if (parameters.Length > 0) { if (parameters[0].ToLower() == "/console") { Application.Run(new ServiceControllerForm(service)); { else { ServiceBase.Run(windowsService); } } } 
+2
source share

Instead of using the Environment.UserInteractive property, change the start method of your service to check the "-console" command line argument. If an argument is present, run it as a normal application. If not, start the service. This is not as automated as checking properties, but it would be easy to add a shortcut to the desktop that will add the "-console" command line argument to you.

As an aside, you need to know that desktop interaction has been disabled in Windows Vista and beyond . If you are using a Windows service that is supposed to interact with the user, the approved way to do this now is to separate your external application from the Windows service and make them communicate using something like WCF.

If you need to debug your Windows service (whether it is running as a service or as an application), put the System.Diagnostics.Debugging.Break() call in your startup method. This prompts you to enter a debugging session. I use this technique to debug my Windows service all the time.

+1
source share

It should also be noted that Environment.UserInteractive always returns true in .NET Core , even if it runs as a Windows service.

At the moment, the best way is this method from ASP.NET Core .

Sources: .NET Core 2.2 .NET Core 3.1

+1
source share

You can check if a process or any of its parent processes is listed as a service:

  var process = System.Diagnostics.Process.GetCurrentProcess(); var parent = process.Parent(); var procIsService = process?.IsService; var parentIsService = parent?.IsService; ... public static class Extensions { private static string FindIndexedProcessName(int pid) { var processName = Process.GetProcessById(pid).ProcessName; var processesByName = Process.GetProcessesByName(processName); string processIndexdName = null; for (var index = 0; index < processesByName.Length; index++) { processIndexdName = index == 0 ? processName : processName + "#" + index; var processId = new PerformanceCounter("Process", "ID Process", processIndexdName); if ((int)processId.NextValue() == pid) { return processIndexdName; } } return processIndexdName; } private static Process FindPidFromIndexedProcessName(string indexedProcessName) { var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName); return Process.GetProcessById((int)parentId.NextValue()); } public static Process Parent(this Process process) { return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id)); } public static bool IsService(this Process process) { using (ManagementObjectSearcher Searcher = new ManagementObjectSearcher( "SELECT * FROM Win32_Service WHERE ProcessId =" + "\"" + process.Id + "\"")) { foreach (ManagementObject service in Searcher.Get()) return true; } return false; } } 
0
source share

All Articles